setVisible: function setVisible(visible) { if (typeof visible !== 'boolean') { throw beez.Error('typeof visible invalid. should be boolean.'); } this.visible = visible; return this; },
loadI18n: function loadI18n(callback) { if (!beez.i18n) { beez.createI18n(); } var self = this; if (beez.utils.is('Object', this.i18n)) { // dynamic load var langs = []; var paths = []; _.each(this.i18n, function (path, lang) { langs.push(lang); paths.push(path); }); require(paths, function () { var list = Array.prototype.slice.call(arguments); for (var i = 0; i < list.length; i++) { var data = {}; data[langs[i]] = list[i]; beez.i18n.add(data); logger.debug('i18n file loaded. path:', paths[i]); } callback && callback(null); }, function (err) { callback && callback(err); }); } else if (beez.utils.is('Function', this.i18n)) { // static load new beez.Bucks() .add(function (err, res, next) { if (0 < self.i18n.length) { self.i18n(function (err, res) { next(err, res); }); } else { next(null, self.i18n()); } }) .add(function (err, res) { if (res) { beez.i18n.add(res); } callback && callback(err, res); }) .end(); } else { callback && callback(new Error('The Controller.i18n, please be defined in Function.')); } return this; },
define('beez.i18n',['require','exports','module','beez.core','beez.utils','handlebars'],function (require, exports, module) { var beez = require('beez.core'); require('beez.utils'); var logger = beez.getLogger('beez.i18n'); var _ = beez.vendor._; if (beez.i18n) { logger.warn('beez.i18n is already loaded.'); return beez.i18n; } var __I18n__ = { setup: function setup() { logger.warn('Setup has already been. beez.i18n'); return this; }, /** * Constructor * WARN: run only once from beez.i18n.setup * * @memberof I18n * @param {Object} options * @see beez.i18n.setup */ initialize: function initialize(options) { /** * @name lang * @memberof I18n * @type {Object} */ this.lang = { base: 'en', // default lang use: undefined // use lang }; /** * @name message * @memberof I18n * @type {Object} */ this.message = {}; /** * Regular expression extract string substitution. * * @name parseReg * @memberof I18n * @type {RegExp} */ //this.parseReg = new RegExp(/\{\{[(0-9a-zA-Z)]*\}\}/); this.parseReg = new RegExp(/\{#{1}[(0-9a-zA-Z)]*\}/); this.lang.use = beez.utils.browser.getLanguage(); // override options options = options || {}; options.lang = options.lang || {}; if (options.lang.base) { this.lang.base = options.lang.base; } if (options.lang.use) { this.lang.use = options.lang.use; } // if (!this.lang.use) { this.lang.use = this.lang.base; } if (options.message) { this.message = options.message; } }, /** * Name of the current language * * @memberof I18n * @instance * @public * @return {String} */ getCurrentLang: function getCurrentLang() { return this.lang.use || this.lang.base; }, /** * Replacement character string extraction. * * @memberof I18n * @instance * @public * @param {String} message * @param {Array} vars * @return {String} */ parse: function (message, vars) { //var list = message.split(/\{\{[(0-9a-zA-Z)]*\}\}/); var list = message.split(this.parseReg); if (list.length === 1 && list[0] === '') { return message; } var res = ''; _.each(list, function (val, idx) { res += val + (vars[idx] || ''); }); return res; }, /** * Alias: I18n.getMessage() * * @memberof I18n * @instance * @public * @return {String} */ __: function __(key) { return this.getMessage(key); }, /** * I get the message corresponding to the current language * * @memberof I18n * @instance * @public * @return {String} */ getMessage: function getMessage(key) { var lang = this.getCurrentLang(); if (!this.message[lang]) { lang = this.lang.base; // set default lang } if (!this.message[lang]) { return ''; // not set!! } var message = this.message[lang][key] || ''; if (!message && this.message[this.lang.base]) { message = this.message[this.lang.base][key] || ''; } var vars = Array.prototype.slice.call(arguments, 1); return this.parse(message, vars); }, /** * Add data to a different message for the current language * * @memberof I18n * @instance * @public * @param {Object} obj * @return {Object} * @example * var res = beez.i18n.add({ja: {"taro": "太郎"}}) * console.log(res) * >> {ja: {"taro": "太郎"}} */ add: function add(obj) { return beez.utils.copyr(this.message, obj); }, /** * Rewrite the message of one language * * @memberof I18n * @instance * @public * @param {String} lang example) 'en' * @param {Object} obj * @return {Object} * @example * var res = beez.i18n.addMessage(ja, {"taro": "太郎"}); * console.log(res) * >> {"taro": "太郎"} */ addMessage: function addMessage(lang, obj) { this.message[lang] = this.message[lang] || {}; return beez.utils.copyr(this.message[lang], obj); }, /** * Delete the message in another language * * @memberof I18n * @instance * @public * @param {String} lang example) 'en' * @param {String} key */ remove: function remove(lang, key) { var obj = this.message[lang]; if (obj && obj[key]) { this.message[lang][key] = null; } else if (obj) { this.message[lang] = null; } else { this.message = {}; } }, /** * remove i18n data * * @memberof I18n * @instance * @public */ dispose: function dispose() { delete this.lang; delete this.message; delete this.parseReg; } }; var I18n = beez.extend( 'beez.i18n', function constructor() { return this.initialize.apply(this, arguments); }, __I18n__); /** * beez.extendThis * * @memberof I18n * @instance * @public */ I18n.extend = beez.extendThis; /** * @see I18n * @memberof beez * @instance * @public */ beez.I18n = I18n; beez.i18n = { /** * i18n initialize * * @memberof I18n * @instance * @name setup * @param {I18n} I18n Class * @param {Object} options constructor/initialize arguments * @public * @example * beez.i18n.setup(null, {lang: {base: 'ja', use: 'ja'}}); * */ setup: function (options, Obj) { if (beez.i18n.initialize) { logger.warn('Setup has already been. beez.i18n'); return beez.i18n; } // clear delete beez.i18n.setup; delete beez.i18n; if (!Obj) { Obj = I18n; } /** * i18n instance * @memberof beez * @instance * @name i18n * @public */ beez.i18n = new Obj(options); return beez.i18n; } }; // --- // Add Handlebars Register Helper var Handlebars = require('handlebars'); /** * i18n Handlebars Register Helper (escape OFF) * * @memberof beez.vendor.Handlebars.Helper * @instance * @name __ * @public */ Handlebars.registerHelper('__', function __(key) { if (beez.i18n) { var vars = Array.prototype.slice.call(arguments, 0, arguments.length - 1); return new Handlebars.SafeString(beez.i18n.getMessage.apply(beez.i18n, vars)); } return ''; }); /** * i18n Handlebars Register Helper (escape ON) * * @memberof beez.vendor.Handlebars.Helper * @instance * @name __ * @public */ Handlebars.registerHelper('__e', function __e(key) { if (beez.i18n) { var vars = Array.prototype.slice.call(arguments, 0, arguments.length - 1); return beez.i18n.getMessage.apply(beez.i18n, vars); } return ''; }); return beez.I18n; });
define(function (require, exports, module) { 'use strict'; var beez = require('beez.core'); var _ = beez.vendor._; var jsonPath = require('beez-mvcr/jsonpath'); var logger = beez.getLogger('beez.mvcr.base'); // ------------------- // ManagerBase /** * It provides a set of methods to deal with it and tree structure simple of Object. * Object of ManagerBase has properties of specific management * * @class * @name ManagerBase * * @example * var manager = new ManagerBase('idx'); * * manager.add('/', {idx:'someObj'}); * manager.get('/someObj') // => {idx:'someObj'} * * manager.add('/', [{idx:'button', name:'a'}, {idx:'button', name:'b'}]); * manager.get('/button') // => [{idx:'button', name:'a'}, {idx:'button', name:'b'}] * manager.get('/button[0]') // => {idx:'button', name:'a'} */ var ManagerBase = beez.extend( 'beez.manager.ManagerBase', function ManagerBase() {}, { /** * @constructor * @memberof ManagerBase * @param {String} idxProp base index name */ constructor: function constructor(idxProp) { /** * Objects that are managed */ this.objs = {}; /** * The assignment to the $ indicates the root */ this.objs[idxProp] = '$'; /** * Index for management */ this._idxProp = idxProp || ''; /** * Run initialize */ this.initialize.apply(this, arguments); }, /** * Constructor * * @memberof ManagerBase */ initialize: function initialize() {}, /** * Get idx of object * * @memberof ManagerBase * @param {ManagerBase} obj * @public * @returns {String} idx */ getIdx: function getIdx(obj) { return obj[this._idxProp]; }, /** * put under control the specified Object * * @memberof ManagerBase * @instance * @param {String} prefix * @param {Object|Array<Object>} obj * * @example * var mainModel = { * follower: [ * followerModel1, * folloewrModel2 * ] * } * * var followerModel3, followingModel, buttonModel; * followerModel3.midx = 'follower'; * followingModel.midx = 'following'; * buttonModel.midx = 'button'; * * manager.model.add('/main', [followerModel, followingModel]); * * -> mainModel : { * follower:[ * followerModel1 * folloewrModel2, * folloewrModel3 * ], * following:[ * followingModel * ] * } * * manager.model.add('/main', button); * -> mainModel : { * follower:[ * followerModel1, * folloewrModel2, * folloewrModel3 * ], * following:[ * followingModel * ], * button: buttonModel * } */ add: function add(prefix, obj) { var parent = this.get(prefix); // search parent from root object // get parent or create waiting object if (!parent) { throw new beez.Error('no parent exists. path: ' + prefix); } if (_.isArray(parent)) { throw new beez.Error('parent is Array. Specify one by using `[number]` selector. parent: ' + parent); } if (_.isArray(obj)) { // add as the children _.each(obj, function (_obj) { _obj.prefix = prefix; // keep prefix var idx = this.getIdx(_obj); if (!parent[idx]) { // make array parent[idx] = []; } parent[idx].push(_obj); }, this); } else { obj.prefix = prefix; // keep prefix var idx = this.getIdx(obj); if (parent[idx]) { throw new beez.Error( 'Obj: adding object to same parent with same index. Add obj as Array to add several objs into same index. idx: ' + this.getIdx(obj)); } parent[idx] = obj; } return this; }, /** * will remove from management the object that is specified in the path * * @memberof ManagerBase * @instance * @param {String} path */ remove: function remove(path) { var objs = this.get(path); // get all children var children = []; var deletes; if (!objs) { return; } // now `views` is always Array if (!_.isArray(objs)) { objs = [objs]; } // array-nize _.each(objs, function (v) { var c = this.getChildrenAll(v); children = children.concat(c); }, this); // list to delete // is children and this views deletes = children.concat(objs); // remove parent's reference _.each(deletes, function (del) { this.deleteFromParent(del); }, this); // call dispose of each views _.each(deletes, function (v) { //v.remove(); v.dispose && v.dispose(); }); }, /** * Returns whether the object can be added to the manager. * * @memberof ManagerBase * @instance * @param {Object} obj * @returns {boolean} */ isAddable: function (obj) { return !!this.getIdx(obj); }, /** * get an Object that is specified in the path * Warnning: which was replaced by the '/' '.'. * no need for root $ * * @see https://github.com/s3u/JSONPath * @memberof ManagerBase * @instance * @param {String} path * @returns {Object} */ get: function get(path) { if (path === undefined || typeof(path) !== 'string') { return undefined; } if (/^\/$/.test(path)) { return this.objs; } var self = this; path = '$' + path.replace(/\//g, '.'); var result = jsonPath( this.objs, path, {wrap: false}, function testAddable(obj) { return self.isAddable(obj); }); if (!result) { return undefined; } return result; }, /** * get the parent. If obj is an array: I get the information from the parent of the first element * * @memberof ManagerBase * @instance * @param {Object|Array.<Object>} obj */ getParent: function getParent(obj) { if (_.isArray(obj)) { return this.get(obj[0].prefix); } return this.get(obj.prefix); }, /** * will remove from the parent, a reference to objct specified. * * @memberof ManagerBase * @instance * @param {Object|Array.<Object>} obj */ deleteFromParent: function deleteFromParent(obj) { if (!obj) { return; } var parent = this.getParent(obj); if (_.isArray(obj)) { delete parent[this.getIdx(obj[0])]; } else { delete parent[this.getIdx(obj)]; } }, /** * get the child list of just under * * @memberof ManagerBase * @instance * @param {Object} obj * @return {Array.<Object>} */ getChildren: function getChildren(obj) { var result = []; var self = this; var _walk = function _walk(list) { _.each(list, function (item) { if (!item) { return; } if (_.isArray(item)) { _walk(item); } else if (self.getIdx(item)) { result.push(item); } }); }; _walk(obj); return result; }, /** * You get as an array all the specified Object (recursively) * * @memberof ManagerBase * @param {Object} data * @return {Array.<Object>} */ getChildrenAll: function getChildrenAll(data) { var result = []; var self = this; var _walk = function _walk(obj) { var list = obj; if (!_.isArray(obj)) { list = _.values(obj); } _.each(list, function (item, idx) { if (!item) { return; } if (_.isArray(item)) { _walk(item); } else if (self.getIdx(item)) { if (!item.prefix || !item.manager) { // Item that is not managed to ignore logger.warn("Manager ignore the Object haven't been manaegd.", item); // result.push(item); // Do not ignore return; } // Ignore the member variable Object has set manually by user. if (obj[self._idxProp] !== '$' && !_.isArray(obj) && item.getParent()[self._idxProp] !== obj[self._idxProp]) { logger.warn("Manager ignore the Object haven't been manaegd.", 'Path that is managed:', self.pathOf(item), // The paths managed the Object of interest 'Path to the specified:', self.pathOf(obj) // The actual path ); return; } _walk(item); // Child is at the beginning of the Array result.push(item); } }); }; // walk start _walk(data); return result; }, /** * Returns the path of the Object being managed. If the Object is array, returns the first element. * * @memberof ManagerBase * @param {String} prefix * @param {Object|Array} obj * @throw {Error} obj is empty array * @throw {Error} object.prefix does not exist * @return {String} */ pathOf: function pathOf(obj) { var prefix = ''; if (_.isArray(obj)) { if (_.isEmpty(obj)) { throw new beez.Error('pathOf: obj is empty array.'); } obj = obj[0]; } prefix = obj.prefix; if (!prefix) { throw new beez.Error('pathOf: object.prefix does not exist.'); } return prefix + ((/^\/$/.test(prefix)) ? '' : '/') + this.getIdx(obj); }, /** * Returns the information Objects are managed. * * @memberof ManagerBase * @return {Object} */ trace: function trace() { var pairs = {}; // all children var all = this.getChildrenAll(this.objs || {}); // for each child, make path & store var self = this; _.each(all, function (obj) { if (!obj) { return; } // make path var key; if (obj.prefix === '/') { // if parent is root key = obj.prefix + self.getIdx(obj); } else { key = obj.prefix + '/' + self.getIdx(obj); } // store if (pairs[key]) { // if already exists if (!_.isArray(pairs[key])) { // at first time, make array pairs[key] = [pairs[key]]; } pairs[key].push(obj); // push } else { // as sigle object pairs[key] = obj; } }); return pairs; }, dispose: function dispose() { delete this.objs; delete this._idxProp; } } ); // ------------------- // Base /** * This is the base class of an Object managed by the Manager. * * @class * @name Base */ var Base = beez.extend( 'beez.mvcr.Base', function Base() {}, { /** * get the first element. Gets the parent. If object is an array, sets the first * * @memberof Base * @instance */ getParent: function getParent() { return this.manager.getParent(this); }, /** * delete the reference of Object from a parent * * @memberof Base * @instance */ deleteFromParent: function deleteFroParent() { return this.manager.deleteFromParent(this); }, /** * I acquire a list of children underneath. * * @memberof Base * @instance * @return {Array.<Object>} */ getChildren: function getChildren() { return this.manager.getChildren(this); }, /** * I acquire all Object of the descendant as an arrangement. * * @memberof Base * @instance * @return {Array.<Object>} */ getChildrenAll: function getChildrenAll() { return this.manager.getChildrenAll(this); }, /** * Sets the object beneath the specified prefix. * * @memberof Base * @param {String} prefix prefix name */ alias: function alias(prefix) { return this.manager.add(prefix, this); } } ); return { ManagerBase: ManagerBase, Base: Base }; });
define(function __Controller__(require, exports, module) { 'use strict'; var beez = require('beez.core'); require('beez.mvcr'); require('beez.i18n'); var logger = beez.getLogger('beez.mvcr.controller'); var _ = beez.vendor._; // ------------------- // ControllerManagerAsync /** * Controller management class, asynchronous * * @class * @name ControllerManagerAsync * @private * @param {ControllerManager} manager * @extends {Bucks} */ var ControllerManagerAsync = beez.Bucks.extend( 'beez.mvcr.ControllerManagerAsync', { /** * Constructor * * @memberof ControllerManagerAsync * @instance */ initialize: function initialize(manager) { this.manager = manager; }, /** * Generation of the Controller * * @memberof ControllerManagerAsync * @instance * @param {String} prefix * @param {Controller|Array<Controller>} Controller Controller Object * @param {Object|Array<Object>} [options] Arguments to the Controller * @return {Controller} */ create: function create(name, Controller, options) { var self = this; return this.then(function createWrap(result, next) { if (!Controller || typeof Controller !== 'function') { throw new beez.Error('Controller does not exist / does not be funciton. Specified name: ' + name); } if (self.manager.controllers[name]) { throw new beez.Error('It is a singleton in the module. name:' + name); } var controller = new Controller(); self.manager.controllers[name] = controller; next(result, self.manager.controllers[name]); }).then(function (controller, next) { controller.loadCSS(function () { // initialize css load next(null, controller); }); }).then(function (controller, next) { controller.loadI18n(function (err) { // initialize i18n load if (err) { logger.error('i18n load error. ', err.message); logger.debug(err.stack); } next(err, controller); }); }); }, /** * Disposes of the instance * * @memberof ControllerManagerAsync */ dispose: function dispose() { logger.trace(this.constructor.name, 'dispose'); delete this.manager; } } ); // ------------------- // ControllerManager /** * Controller management class. * * @class * @name ControllerManager */ var ControllerManager = beez.extend( 'beez.mvcr.ControllerManager', function constructor() { return this.initialize(); }, { /** * Constructor * * @memberof ControllerManager * @instance */ initialize: function initialize() { this.controllers = {}; }, /** * Generating ControllerManagerAsync * * @memberof ControllerManager * @instance * @return {ControllerAsync} */ async: function async() { return new ControllerManagerAsync(this); }, /** * Remove controller * * @memberof ControllerManager * @instance * @param {String} name jsonPath name * @return {ControllerManager} */ remove: function remove(name) { var obj = this.get(name); if (!obj) { return this; } delete this.controllers[name]; return this; }, /** * From path, acquire Controller. * * @memberof ControllerManager * @instance * @param {String} name jsonPath name * @return {Controller} */ get: function get(name) { return this.controllers[name]; }, /** * Disposes of the instance * * @memberof ControllerManager * @instance */ dispose: function () { logger.trace(this.constructor.name, 'dispose'); delete this.controllers; } }); // ------------------- // Controller /** * Controller class. * * @namespace beez.mvcr * @class * @name Controller */ var Controller = beez.extend( 'beez.mvcr.Controller', function constructor() { this.initialize.apply(this, arguments); }, { /** * Constructor * * @memberof Controller * @instance */ initialize: function initialize() { }, /** * automatic loading of i18n data. * @memberof Controller * @param {function} callback */ i18n: function i18n() {}, /** * automatic loading of i18n. * * @memberof Controller * @param {function} callback Completion callback * @instance * @return {Controller} */ loadI18n: function loadI18n(callback) { if (!beez.i18n) { beez.createI18n(); } var self = this; if (beez.utils.is('Object', this.i18n)) { // dynamic load var langs = []; var paths = []; _.each(this.i18n, function (path, lang) { langs.push(lang); paths.push(path); }); require(paths, function () { var list = Array.prototype.slice.call(arguments); for (var i = 0; i < list.length; i++) { var data = {}; data[langs[i]] = list[i]; beez.i18n.add(data); logger.debug('i18n file loaded. path:', paths[i]); } callback && callback(null); }, function (err) { callback && callback(err); }); } else if (beez.utils.is('Function', this.i18n)) { // static load new beez.Bucks() .add(function (err, res, next) { if (0 < self.i18n.length) { self.i18n(function (err, res) { next(err, res); }); } else { next(null, self.i18n()); } }) .add(function (err, res) { if (res) { beez.i18n.add(res); } callback && callback(err, res); }) .end(); } else { callback && callback(new Error('The Controller.i18n, please be defined in Function.')); } return this; }, /** * automatic loading of css. * * @memberof Controller * @param {function} callback Completion callback * @instance * @return {Controller} */ loadCSS: function loadCSS(callback) { var paths = this.css; if (!paths || paths.length < 1) { return callback && callback(); } var self = this; var tasks = _.map(paths, function task(p) { return function t(err, res, next) { beez.manager.css.async() .load(p) .end(function (err1, res1) { next(err, res1[0]); }, function (err2) { next(err2); }); }; }); var b = new beez.Bucks(); b.parallel(tasks) .end(function (err, ress) { callback && callback(err, ress); }); return this; }, /** * Disposes of the instance * * @memberof Controller */ dispose: function dispose() { logger.trace(this.constructor.name, 'dispose'); delete this.constructor.prototype.css; } } ); /** * extend function * * @memberof Controller * @function * @param {String} [name] instance name * @param {Object} childProto prototypes * @borrows beez.extendThis as extend * @example * var MyController = Controller.extend( * 'myapp.MyController', * { * bar: function bar() {} * } * ); */ Controller.extend = beez.extendThis; return { Controller: Controller, ControllerManager: ControllerManager, ControllerManagerAsync: ControllerManagerAsync }; });
define('beez-utils/browser',['require','exports','module','beez.core','backbone','beez.ua'],function (require, exports, module) { var beez = require('beez.core'); var global = beez.global || global; var _ = beez.vendor._; var $ = beez.vendor.$; var Backbone = require('backbone'); /** * ブラウザの情報を取得するchainです。 * ブラウザの情報は取得するためにdelayが必要な場合があり、 * そのような情報をasync chainの形で取得できるようになっています * @class * @name BrowserAsync */ var BrowserAsync = beez.Bucks.extend( 'beez.utils.BrowserAsync', { initialize: function initialize(browser) { this.browser = browser; }, dispose: function dispose() { delete this.browser; }, /** * アドレスバーを隠します * delayをかけるのでonload時などに呼んでも動作します * @memberof BrowserAsync * @param {int} delay delay time(ms) * @instance * @return {BrowserAsync} */ hideAddress: function hideAddress(delay) { delay = delay || 100; return this .delay(delay) // delayを挟む .then(function scroll() { window.scroll(0, 0); }); } /** * 指定したelementのcomputedStyleを返します * @memberof BrowserAsync * @instance * @param {HTMLElement} elem * @return {BrowserAsync} */ //getComputedStyle: function getComputedStyle(elem) { // var self = this; // return this.then(function chainValue() { // return self.browser.getComputedStyleSync(elem); // }); //}, /** * windowサイズを返します * @memberof BrowserAsync * @instance * @return {BrowserAsync} */ //getWindowSize: function getWindowSize() { // var self = this; // return this.then(function chainValue() { // return self.browser.getWindowSizeSync(); // }); //} }); var __Browser__ = { _prevOrientation: global.orientation, _initOrientation: global.orientation, /** * @memberof Browser * @instance */ initialize: function initialize() { this.startHandleOrientation(); }, /** * 画面の回転イベントのbindを開始します。 * @memberof Browser * @instance */ startHandleOrientation: function startHandleOrientation() { // Androids don't have orientation change event var evName = ('onorientationchange' in window) ? 'orientationchange' : 'resize'; // listen window's event var self = this; $(global).on(evName, function (ev) { var o = global.orientation; if (self._prevOrientation !== o) { // trigger event self.trigger( 'change:orientation', { prev: self._prevOrientation, current: o, init: self._initOrientation === o ? true : false } ); self._prevOrientation = o; } }); }, /** * 指定されたelementのcomputedStyleを返します */ getComputedStyle: function getComputedStyle(elem) { return document.defaultView.getComputedStyle(elem, ''); }, /** * 指定されたelementのcomputedStyleを返すchainを返します * then(callback)で値を受け取れます */ //getComputedStyle: function getComputedStyle(elem) { // return new BrowserAsync(this).getComputedStyle(elem); //}, async: function async() { return new BrowserAsync(this); }, /** * Addressbarを隠すchainを返します */ hideAddress: function hideAddress(delay) { return new BrowserAsync(this).hideAddress(delay); }, /** * windowサイズを返すchainを返します。 * then(callback)で値を受け取れます * */ //getWindowSize: function getWindowSize() { // return new BrowserAsync(this).getWindowSize(); //}, /** * windowサイズを返します */ getWindowSize: function getWindowSize() { return {width: window.innerWidth, height: window.innerHeight}; }, /** * @memberof Browser * @borrows Browser~ua as Browser#ua * @type {Browser~ua} */ ua: {}, // injected below /** * Navigator Language default) 'en' * @memberof Browser * @return {String} */ getLanguage: function getLanguage() { var lang = navigator.language || navigator.browserLanguage || navigator.systemLanguage || navigator.userLanguage; // android 2.3 only!!!! if (this.ua.android23 && ua.browser.lang) { return ua.browser.lang; } if (!lang) { return undefined; } return lang.substr(0, 2); } //ua: require('beez.ua') }; var ua = require('beez.ua'); ua.setup(); // default browser useragent __Browser__.ua = ua; /** * ブラウザ情報の取得のためのクラスです。 * 画面方向が変わるとchange:orientation イベントを発します * @class * @name Browser * @extends {Backbone.Events} */ var Browser = beez.extend( 'beez.utils.Browser', function Browser() {}, Backbone.Events, __Browser__ ); return Browser; });
define('beez.utils',['require','exports','module','beez.core','beez-utils/browser','beez-utils/timer'],function (require, module, exports) { var beez = require('beez.core'); var _ = beez.vendor._; var logger = beez.getLogger('beez.utils'); // double load check if (beez.utils) { logger.warn('beez.utils already defined.'); return beez.utils; } var __Utils__ = { initialize: function initialize(opts) { var Browser = require('beez-utils/browser'); var Timers = require('beez-utils/timer'); /** * instance of Browser * @name browser * @memberof beez.utils * @type {Browser} */ this.browser = new Browser(); /** * class of Timers * @name Timers * @memberof beez.utils * @type {Timers} */ this.Timers = Timers; this.none = beez.none; /** * pixel ratio * * @name pixelRatio * @memberof beez.utils * @type {Timers} */ this.pixelRatio = global.devicePixelRatio || 1; //this.htmlRatio = this.pixelRatio; }, /** * recursively copy the properties of src to dst * dst properties = object : merge * other properties (array, string, number .. ) : override * * @name copyr * @memberof beez.utils * @param {Object} dst * @param {Object} src * @return Object */ copyr: function copyr(dst, src) { // for each props in src for (var k in src) { var dstProp = dst[k]; var srcProp = src[k]; if (_.isObject(dstProp) && !_.isArray(srcProp)) { copyr(dst[k], src[k]); // cp recursively } else { dst[k] = src[k]; // override/add property 'k' } } return dst; }, /** * To determine the type. * * @name is * @memberof beez.utils * @param {String} type * @param {Object} obj * @return boolean * @example * > beez.utils.is('Null'null) => true * > beez.utils.is('Array', []) => true * > beez.utils.is('Function', function () {}) => true * > beez.utils.is('String', "") => true * > beez.utils.is('Number', 1) => true * > beez.utils.is('Boolean', true) => true * > beez.utils.is('Number', Date.now()) => true * > beez.utils.is('RegExp', /^$/) => true * > beez.utils.is('Null', null) => true * > beez.utils.is('Undefined', undefined) => true * */ is: function is(type, obj) { var clas = Object.prototype.toString.call(obj).slice(8, -1); return obj !== undefined && obj !== null && clas === type; } }; var Utils = beez.extend( 'beez.Utils', function constructor() { return this.initialize(); }, __Utils__); // shortcut funciton os 'underscore.js#isXXX' function _.each(['Equal', 'Empty', 'Element', 'Arguments', 'Function', 'String', 'Number', 'Finite', 'Boolean', 'Date', 'RegExp', 'NaN', 'Null', 'Undefined'], function (type) { Utils.prototype['is' + type] = _['is' + type]; }); // shortcut function of 'is()' function _.each(['Object', 'Array'], function (type) { Utils.prototype['is' + type] = function (obj) { return this.is.apply(this, [type, obj]); }; }); beez.utils = new Utils(); return beez.utils; });
define('beez-utils/timer',['require','exports','module','beez.core','beez-utils/uid'],function (require, exports, module) { var beez = require('beez.core'); var _ = beez.vendor._; var logger = beez.getLogger('timer'); var UID = require('beez-utils/uid'); var uid = new UID(); var BEEZ_TIMER_ID_PROP = 'beez_utils_timer_id'; /** * setIntervalひとつに複数のtimerを設定できる仕組みです。 * 現在は誤差100msとなっています */ var Timers = function () { this.running = false; this._callbacks = {}; this._timerId = 0; }; Timers.prototype = { /** * timeoutを追加する。 * @param {Function} callback * @param {int} ms millisecond to timeout * @param {Object} context * @return {string} timerId */ addTimeout: function addTimeout(callback, ms, context) { var id = uid.create(); callback[BEEZ_TIMER_ID_PROP] = id; var callbackInfo = { timer_id: id, callback: callback, interval: ms, time: Date.now() + ms, context: context, type: 'timeout', canceller: function canceller() { this.type = 'canceled'; } }; //_.bindAll(callbackInfo); _.bindAll.apply(this, [callbackInfo].concat(_.methods(callbackInfo))); this._callbacks[id] = callbackInfo; this.start(); return id; }, /** * intervalを追加する。 * @param {Function} callback * @param {Object} context * @return {String} timerId */ addInterval: function addInterval(callback, ms, context) { var id = uid.create(); callback[BEEZ_TIMER_ID_PROP] = id; var callbackInfo = { timer_id: id, callback: callback, interval: ms, time: Date.now() + ms, context: context, type: 'interval', canceller: function canceller() { this.type = 'canceled'; } }; //_.bindAll(callbackInfo); _.bindAll.apply(this, [callbackInfo].concat(_.methods(callbackInfo))); this._callbacks[id] = callbackInfo; this.start(); return id; }, /** * intervalを解除します * @param {Function|String} fnOrId addIntervalしたfunction, もしくは * その際に返ったtimer_id */ clearInterval: function clearInterval(fnOrId) { var id; if (typeof fnOrId === 'function' && fnOrId[BEEZ_TIMER_ID_PROP]) { id = fnOrId[BEEZ_TIMER_ID_PROP]; } else { id = fnOrId; } var callbackInfo = this._callbacks[id]; if (!callbackInfo) { throw new Error('no callback to clear'); } callbackInfo.canceller(); }, /** * timeoutを解除します。clearIntervalと違うのは * すでにtimeoutしているなどしてclearしようとしたタイマーが * 存在しなかった場合も静かに無視します。 * @param {Function|String} fnOrId addTimerしたfunction, もしくは * その際に返ったtimer_id */ clearTimeout: function clearInterval(fnOrId) { var id; if (typeof fnOrId === 'function' && fnOrId[BEEZ_TIMER_ID_PROP]) { id = fnOrId[BEEZ_TIMER_ID_PROP]; } else { id = fnOrId; } var callbackInfo = this._callbacks[id]; if (!callbackInfo) { return; } callbackInfo.canceller(); }, _tick: function _tick() { var now = Date.now(); var self = this; _.each(this._callbacks, function (info) { if (info.time < now) { // fire if (info.type !== 'canceled') { if (info.context) { info.callback.call(null, info.context); } else { info.callback.call(); } } if (info.type !== 'interval') { delete self._callbacks[info.timer_id]; } info.time = now + info.interval; } return true; }); if (!_.keys(this._callbacks).length) { this.stop(); } }, /** * timerをstartします。通常はaddTimeout/addIntervalした際に * 自動的に実行されるので直接実行する必要はありません */ start: function start() { if (this.running) { return; } this.running = true; var self = this; var tickWrapper = function tickWrapper() { if (self.running) { self._tick(); self._timerId = setTimeout(tickWrapper, 100); // @TODO } }; tickWrapper(); }, /** * timerをstopします。またtimeoutが実行され終わったり * clearTimeout/clearIntervalによって実行待ちのコールバックが * ひとつも無くなった場合は自動的にstopが実行されます */ stop: function stop() { this.running = false; clearTimeout(this._timerId); } }; return Timers; });
define(function __View__(require, exports, module) { 'use strict'; var beez = require('beez.core'); require('beez.utils'); var _ = beez.vendor._; var Backbone = require('backbone'); var base = require('beez-mvcr/base'); var Base = base.Base; var ManagerBase = base.ManagerBase; var logger = beez.getLogger('beez.mvcr.view'); /** * View management class, asynchronous * * @class * @name Creator * @extends {Bucks} */ var ViewManagerAsync = beez.Bucks.extend( 'beez.mvcr.ViewManagerAsync', { initialize: function initialize(manager) { this.manager = manager; }, /** * set root * * @memberof ViewManagerAsync * @instance * @param {View} root vidx is '@' must * @return {ViewManagerAsync} */ root: function root(root) { var self = this; return this.then(function () { return self.manager.root(root); }); }, /** * Generate View. * * @memberof ViewManagerAsync * @instance * @param {String} prefix parent prefix * @param {View|Array<View>} View Generate View object(s). * @param {Object} [options] Argument of the View object. * @return {ViewManagerAsync} */ create: function create(prefix, View, options) { var self = this; return this.then(function () { var v = self.manager.create(prefix, View, options); var current = _.isArray(v) ? v[0] : v; return current; }); }, /** * View is generated as a child of the View object generated before the chain. * * @memberof ViewManagerAsync * @instance * @param {View|Array<View>} View Generate View object. * @param {Object} [options] Argument of the View object. * @return {ViewManagerAsync} */ child: function child(View, options) { var self = this; return this.then(function (current) { var prefix = self.manager.pathOf(current); var v = self.manager.create(prefix, View, options); current = _.isArray(v) ? v[0] : v; return current; }); }, /** * Get the parent View. * * @memberof ViewManagerAsync * @instance * @return {ViewManagerAsync} */ parent: function parent() { var self = this; return this.then(function (current) { var parent = self.manager.getParent(current); if (parent) { throw new beez.Error('get parent failed. current: ' + current); } current = parent; return current; }); }, /** * The child and its brother of the parents of View. * * @memberof ViewManagerAsync * @instance * @param {object} [options] Argument of the View object. * @return {Creator} */ bro: function bro(brother, options) { return this.parent().child(brother, options); }, /** * Disposes of the instance * * @memberof ViewManagerAsync * @override called when this chain ended */ dispose: function dispose() { logger.trace(this.constructor.name, 'dispose'); delete this.manager; delete this.current; delete this.root; } } ); /** * ViewManager Class * * @class * @name ViewManager */ var ViewManager = beez.extend( 'beez.mvcr.ViewManager', ManagerBase, { /** * Constructor * * @memberof ViewManager * @instance */ initialize: function initialize() { ViewManager.__super__.initialize.apply(this, arguments); }, /** * Generating ViewManagerAsync * * @memberof ViewManager * @instance * @return {ViewManagerAsync} */ async: function async() { return new ViewManagerAsync(this); }, /** * Set the Root View * * @memberof ViewManager * @instance * @param {View} RootView vidx is '@' must * @return {View} */ root: function root(RootView) { this.add('/', new function DummyRootView() { this.vidx = '@'; }); var rootView = new RootView(this); var rootChildren = this.getChildren(this.get("/@")); // save this.remove('/@'); var root = this.get('/@'); if (root) { throw new beez.Error('root already exists!'); } if (rootView.vidx !== '@') { throw new beez.Error('roots vidx must be "@"'); } this.add('/', rootView); // re-save for (var i = 0; i < rootChildren.length; i++) { this.add('/@', rootChildren[i]); } return rootView; }, /** * Generate View. * * @memberof ViewManager * @instance * @param {String} prefix parent prefix * @param {View|Array<View>} View Generate View object(s). * @param {Object} [options] Argument of the View object. * @return {Array} */ create: function create(prefix, View, options) { if (!View || (!_.isArray(View) && typeof View !== 'function')) { throw new beez.Error('View does not exist / does not be funciton. Specified prefix: ' + prefix); } if (!prefix) { throw new beez.Error('No prefix specified. Creating:' + View.name); } if (prefix.indexOf('/@') < 0) { throw new beez.Error('prefix must started by "/@". Creating:' + View.name); } if (!this.get(prefix)) { // no parent throw new beez.Error('no parent exists. prefix: ' + prefix + ' , Please consider constructing view in Controller, or in #beforeOnce and so on.'); } if (_.isArray(View)) { return this._createArray(prefix, View, options); } return this._createObj(prefix, View, options); }, /** * Generate View(Object). * * @memberof ViewManager * @instance * @private */ _createObj: function _createObj(prefix, View, options) { var v = new View(this, options); if (!this.isAddable(v)) { throw new beez.Error('index does not exists in the View. :' + v); } this.add(prefix, v); return v; }, /** * Generate View(Array). * * @memberof ViewManager * @instance * @private */ _createArray: function _createArray(prefix, Views, options) { var self = this; // forced array if (options && !_.isArray(options)) { options = [options]; } var instances = []; _.each(Views, function (C, idx) { // new var params = options ? options[idx] : undefined; var v = new C(self, params); instances.push(v); }); _.each(instances, function (view) { // check if (!this.isAddable(view)) { throw new beez.Error('index does not exists in the View. :' + view); } }, this); this.add(prefix, instances); return instances; }, /** * remove * * @name remove * @memberof ViewManager * @instance * @param {String} path */ remove: function remove(path) { ViewManager.__super__.remove.apply(this, arguments); }, /** * Dispose view and self from management. * * @memberof ViewManager * @instance */ dispose: function dispose() { logger.trace(this.constructor.name, 'dispose'); var managedChildren = this.getChildrenAll(this.objs); _.each(managedChildren, function (key) { key.dispose(); }); ViewManager.__super__.dispose.apply(this, arguments); } } ); // ------------------- // View /** * View class Asynchronous * * @class * @name ViewAsync * @extends {Bucks} * @private */ var ViewAsync = beez.Bucks.extend( 'beez.mvcr.ViewAsync', { /** * @memberof ViewAsync * @param {View} root Root View */ initialize: function initialize(root) { this._root = root; }, /** * Processing is performed by the flow of [beforeOnce -> before -> render -> after -> afterOnce]. * * @memberof Renderer * @instance * @param {BeezView} view * @param {boolen} [renderChildren=true] */ _render: function _render(view) { // start with view this.then(function () { return view; }); if (!view.state.isBeforeOnce) { // check flag // call beforeOnce this.then(function beforeOnce(view, next) { if (!view.visible) { logger.debug('view', view.vidx, 'is not visible. skip `beforeOnce`.'); next(null, view); // skip return; } // if `beforeOnce` have `done` as a param if (view.beforeOnce.length > 0) { view.beforeOnce(function wrappedDone() { view.state.isBeforeOnce = true; next(null, view); }); return; } // else exec as sync view.beforeOnce(); view.state.isBeforeOnce = true; next(null, view); }); } // call before this.then(function before(view, next) { if (!view.visible) { logger.debug('view', view.vidx, 'is not visible. skip `before`.'); next(null, view); // skip return; } // if `before` have `done` as a param if (view.before.length > 0) { view.before(function wrappedDone() { next(null, view); }); return; } // else exec as sync view.before(); next(null, view); }); // call render this.then(function render(view, next) { if (!view.visible) { logger.debug('view', view.vidx, 'is not visible. skip `render`.'); next(null, view); // skil return; } // if `render` have `done` as a param if (view.render.length > 0) { view.render(function wrappedDone() { next(null, view); }); return; } // else exec as sync view.render(); next(null, view); return; }); // call after this.then(function after(view, next) { if (!view.visible) { logger.debug('view', view.vidx, 'is not visible. skip `after`.'); next(null, view); // skip return; } // if `afterOnce` have `done` as a param if (view.after.length > 0) { view.after(function wrappedDone() { next(null, view); }); return; } // else exec as sync view.after(); next(null, view); return; }); if (!view.state.isAfterOnce) { // check flag // call afterOnce this.then(function afterOnce(view, next) { if (!view.visible) { logger.debug('view', view.vidx, 'is not visible. skip `afterOnce`.'); next(null, view); // skip return; } // if `afterOnce` have `done` as a param if (view.afterOnce.length > 0) { view.afterOnce(function wrappedDone() { view.state.isAfterOnce = true; next(null, view); }); return; } // else exec as sync view.afterOnce(); view.state.isAfterOnce = true; next(null, view); return; }); } this.then(function rendered(view, next) { if (!view.visible) { logger.debug('view', view.vidx, 'is not visible. skip trigger events beez:view:render'); next(null, view); return; } logger.debug('view', view.vidx, 'is rendered. trigger beez:view:render'); view.trigger('beez:view:render'); next(null, view); return; }); return this; }, /** * Delete the View. * * @memberof ViewAsync * @instance * @param {View} view * @return {View} */ _remove: function _remove(view) { this.then(function () { return view; }); this.then(function conceal(view, next) { // if `conceal` have `done` as a param if (view.conceal.length > 0) { view.conceal(function wrappedDone() { next(null, view); }); return; } // else exec as sync view.conceal(); next(null, view); return; }); this.then(function remove(view, next) { view.remove(); logger.debug('view', view.vidx, 'is removed. trigger beez:view:remove'); view.trigger('beez:view:remove'); next(null, view); return; }); return this; }, /** * Handles the rendering of the View. * Child elements are rendered. * * visible=false : Skip the rendering, including the child elements. * showChildren=false : Only the specified view is rendered, child elements are not rendered. * * @memberof ViewAsync * @instance * @public * @param {boolean} [options.showChildren=true] if not show children, set false * @param {Function} options.filter show filtered view by the function * @return {ViewAsync} * @throws {beez.Error} render root is not set */ show: function show(options) { if (!this._root) { throw new beez.Error('render root is not set. initialize renderer with root view parameter.'); } options = options || {}; // TODO: Put out in the future if (beez.utils.isBoolean(options)) { options = { showChildren: options }; } if (options.showChildren === undefined) { options.showChildren = true; } return this._show(this._root, options); }, /** * Handles the rendering of the View. * Child elements are rendered. * * visible=false : Skip the rendering, including the child elements. * showChildren=false : Only the specified view is rendered, child elements are not rendered. * * * @memberof ViewAsync * @instance * @private * @param {View} view view to show * @param {boolean} [options.showChildren=true] if not show children, set false * @param {Function} options.filter show filtered view by the function * @return {ViewAsync} */ _show: function _show(view, options) { logger.debug('showing', view.vidx); var self = this; var children = view.getChildren(); if (options.filter) { logger.debug('filtering', view.vidx); children = _.filter(children, options.filter); } this._render(view); if (children.length > 0 && options.showChildren) { children.sort(function (a, b) { if (a.order < b.order) { return -1; } if (a.order > b.order) { return 1; } return 0; }); _.each(children, function (v) { self._show(v, options); }); } return this; }, /** * Handles the rendering of the View. * Child elements are rendered. * * want to hide the View. And hide also to the child element * hideChildren=false: Child element is not hidden. * * @memberof ViewAsync * @instance * @private * @param {View} view view to hide * @param {boolean} [options.hideChildren=true] if set false, children not be removed * @param {Function} options.filter hide filetered view by the function * @return {ViewAsync} */ hide: function hide(options) { if (!this._root) { throw new beez.Error('render root is not set. initialize renderer with root view parameter.'); } options = options || {}; // TODO: Put out in the future if (beez.utils.isBoolean(options)) { options = { hideChildren: options }; } if (options.hideChildren === undefined) { options.hideChildren = true; } return this._hide(this._root, options); }, /** * Handles the rendering of the View. * Child elements are rendered. * * want to hide the View. And hide also to the child element * hideChildren=false: Child element is not hidden. * * @memberof ViewAsync * @instance * @private * @param {View} view view to hide * @param {boolean} [options.hideChildren=true] if set false, children not be removed * @param {Function} options.filter hide filetered view by the function * @return {ViewAsync} */ _hide: function _hide(view, options) { logger.debug('hiding', view.vidx); var self = this; var children = view.getChildren(); if (options.filter) { logger.debug('filtering', view.vidx); children = _.filter(children, options.filter); } if (children.length > 0 && options.hideChildren) { children.sort(function (a, b) { if (a.order < b.order) { return 1; } if (a.order > b.order) { return -1; } return 0; }); _.each(children, function (v) { self._hide(v, options); }); } // case of single view logger.debug('hiding', view.vidx); this._remove(view); return this; }, /** * Disposes of the instance * * @memberof ViewAsync * @instance */ dispose: function dispopse() { logger.trace(this.constructor.name, 'dispose'); delete this._root; } } ); /** * View class * * @namespace beez.mvcr * @class * @name View * @extends {Backbone.View} * @see Backbone.View */ var View = beez.extend( 'beez.mvcr.View', Base, Backbone.View.prototype, { /** * Constructor * * @memberof View */ constructor: function constructor() { if (arguments.length < 1) { throw new beez.Error('In order to create a View, requires one arguments.'); } this.manager = arguments[0]; /** * Management flag * @memberof View */ this.state = { isBeforeOnce: false, isAfterOnce: false }; /** * Skip rendering flag * * @memberof View * @instance * @property visible * @type {boolean} */ this.visible = true; View.__super__.constructor.apply(this, Array.prototype.slice.call(arguments, 1)); }, /** * call initialize method * * @memberof View * @name initialize * @override Backbone.View.initialize() */ initialize: function initialize() { // call Backbone.View.initialize() View.__super__.initialize.apply(this, arguments); }, /** * Index for View management. * * @memberof View * @instance * @property vidx */ vidx: undefined, // View Index key /** * HTMLElement * @see Backbone#View * * @memberof View * @instance * @property el */ el: undefined, /** * The order from the parent View * * @memberof View * @instance * @property order */ order: 0, /** * The function performed before render is performed when a show function is performed. (only once) * Until next runs to waiting after that function, to define a next as an argument, to delay the process. * * @memberof View * @instance * @function * @param {Function} [next] * @example * beforeOnce: function beforeOnce(next) { * somethingAsync(function() { * next(); * }); * } * */ beforeOnce: beez.none, /** * The function performed before render is performed when a show function is performed. * Until next runs to waiting after that function, to define a next as an argument, to delay the process. * * @memberof View * @instance * @function * @param {Function} [next] * @example * before: function before(next) { * somethingAsync(function() { * next(); * }); * } */ before: beez.none, /** * Execute after this view have been rendered. * You can delay processes to give `next` in arugument, then processes made to be delayed untill for call `next`. * * @memberof View * @instance * @function * @param {Function} [next] * @example * after: function after(next) { * somethingAsync(function() { * next(); * }); * } */ after: beez.none, /** * Execute once after this view have been rendered. * You can delay processes to give `next` in arugument, then processes made to be delayed untill for call `next`. * * @memberof View * @instance * @function * @param {Function} [next] * @example * afterOnce: function afterOnce(next) { * somethingAsync(function() { * next(); * }); * } */ afterOnce: beez.none, /** * Generate async class * * @memberof View * @instance * @return {ViewAsync} */ async: function async() { return new ViewAsync(this); }, /** * Return existence of HTMLElement on DOM tree in this view. * * @memberof View * @instance * @function * @return {boolean} */ isRendered: function isRendered() { return !!this.el && !!this.el.parentElement; }, /** * set visible * * @memberof View * * @param {boolean} visible * @throw {Error} typeof visible invalid. should be boolean * @return {View} this */ setVisible: function setVisible(visible) { if (typeof visible !== 'boolean') { throw beez.Error('typeof visible invalid. should be boolean.'); } this.visible = visible; return this; }, /** * Disposes of the instance and remove HTMLElement * and undelegate event on all view. * * @memberof View * @instance * @override Backbone.View.undelegateEvents * @return */ dispose: function dispose() { logger.trace(this.constructor.name, 'dispose'); this.remove(); // call Backbone.undelegateEvents method View.__super__.undelegateEvents.apply(this, arguments); delete this.manager; delete this.state; delete this.visible; delete this.cid; delete this.options; delete this.$el; delete this.model; delete this.collection; delete this.el; // delete this.id; delete this.attributes; delete this.className; delete this.tagName; // delete this.events; // call Base.dispose() // View.__super__.dispose.call(this); }, /** * The function performed before remove is performed * Until next runs to waiting after that function, to define a next as an argument, to delay the process. * * @memberof View * @instance * @function * @param {Function} [next] * @example * conceal: function conceal(next) { * somethingAsync(function() { * next(); * }); * } */ conceal: beez.none, /** * Remove HTMLElement. * * @memberof View * @function * @override Backbone.View.remove * @return */ remove: function remove() { // call Backbone.remove View.__super__.remove.apply(this, arguments); } } ); /** * @memberof View * @function * @param {String} [name] * @param {Object} childProto * @borrows beez.extendThis as extend * @example * var MyView = View.extend( * 'myapp.MyView', * { * vidx: 'foo', * bar: function bar() {} * } * ); */ View.extend = beez.extendThis; return { View: View, ViewAsync: ViewAsync, ViewManager: ViewManager, ViewManagerAsync: ViewManagerAsync }; });
define(function __MVCR__(require, exports, module) { 'use strict'; var beez = require('beez.core'); var logger = beez.getLogger('beez.mvcr'); if (beez.mvcr) { logger.debug('beez.mvcr already defined.'); return beez.mvcr; } var Handlebars = require('handlebars'); /** * Shortcut function * Handlebars.templates[] * @memberof beez * @function * @name getTemplate * @param {String} name * @returns {Function} handlebars template function */ beez.getTemplate = function getTemplate(name) { return Handlebars.templates[name]; }; var __MVCR__ = { initialize: function () { var model = require('beez-mvcr/model'); var modic = require('beez-mvcr/modic'); var view = require('beez-mvcr/view'); var controller = require('beez-mvcr/controller'); var router = require('beez-mvcr/router'); var css = require('beez-mvcr/cssmanager'); var image = require('beez-mvcr/imagemanager'); var base = require('beez-mvcr/base'); /** * @name Model * @memberof beez.mvcr * @borrows Model * @type {Model} */ this.Model = model.Model; /** * @name ModelManager * @memberof beez.mvcr * @borrows ModelManager * @type {ModelManager} */ this.ModelManager = model.ModelManager; // if you want to extend /** * @name ModelManagerAsync * @memberof beez.mvcr * @borrows ModelManagerAsync * @type {ModelManagerAsync} */ this.ModelManagerAsync = model.ModelManagerAsync; // if you want to extend /** * @name Collection * @memberof beez.mvcr * @borrows Collection * @type {Collection} */ this.Collection = model.Collection; /** * @name Modic * @memberof beez.mvcr * @borrows Modic * @type {Modic} */ this.Modic = modic.Modic; /** * @name View * @memberof beez.mvcr * @borrows View * @type {View} */ this.View = view.View; /** * @name View * @memberof beez.mvcr * @borrows ViewAsync * @type {ViewAsync} */ this.ViewAsync = view.ViewAsync; /** * @name View * @memberof beez.mvcr * @borrows ViewManager * @type {View} */ this.ViewManager = view.ViewManager; // if you want to extend /** * @name View * @memberof beez.mvcr * @borrows ViewManagerAsync * @type {ViewManagerAsync} */ this.ViewManagerAsync = view.ViewManagerAsync; // if you want to extend /** * @name Controller * @memberof beez.mvcr * @borrows Controller * @type {Controller} */ this.Controller = controller.Controller; /** * @name Controller * @memberof beez.mvcr * @borrows ControllerManager * @type {Controller} */ this.ControllerManager = controller.ControllerManager; // if you want to extend /** * @name Controller * @memberof beez.mvcr * @borrows ControllerManagerAsync * @type {ControllerAsync} */ this.ControllerManagerAsync = controller.ControllerManagerAsync; // if you want to extend /** * @name Router * @memberof beez.mvcr * @borrows Router * @type {Router} */ this.Router = router.Router; /** * @name RouterManager * @memberof beez.mvcr * @borrows RouterManager * @type {RouterManager} */ this.RouterManager = router.RouterManager; // if you want to extend /** * @name CSSManager * @memberof beez.mvcr * @borrows CSSManager * @type {CSSManager} */ this.CSSManager = css.CSSManager; // if you want to extend /** * @name CSSManagerAsync * @memberof beez.mvcr * @borrows CSSManagerAsync * @type {CSSManagerAsync} */ this.CSSManagerAsync = css.CSSManagerAsync; // if you want to extend /** * @name ImageManager * @memberof beez.mvcr * @borrows ImageManager * @type {ImageManager} */ this.ImageManager = image.ImageManager; // if you want to extend /** * @name ImageManagerAsync * @memberof beez.mvcr * @borrows ImageManagerAsync * @type {ImageManagerAsync} */ this.ImageManagerAsync = image.ImageManagerAsync; // if you want to extend /** * @name ManagerBase * @memberof beez.mvcr * @borrows ManagerBase * @type {ManagerBase} */ this.ManagerBase = base.ManagerBase; /** * @name Base * @memberof beez.mvcr * @borrows Base * @type {Base} */ this.Base = base.Base; } }; var MVCR = beez.extend( 'beez.MVCR', function constructor() { return this.initialize(); }, __MVCR__); var mvcr = new MVCR(); // Add to beez object. beez.mvcr = mvcr; beez.Model = mvcr.Model; beez.Collection = mvcr.Collection; beez.Modic = mvcr.Modic; beez.View = mvcr.View; beez.Controller = mvcr.Controller; beez.Router = mvcr.Router; // Backbone shortcut var Backbone = require('backbone'); /** * Backbone.history short cut. * @name history * @memberof beez */ beez.history = Backbone.history; // // ---- // Managers // var mconfig = beez.config.manager || {}; var __Manager__ = { initialize: function () { /** * setuped flag * @memberof beez.manager * @name setuped * @type {Boolean} */ this.setuped = false; /** * ModelManager instance * @memberof beez.manager * @name model * @alias m * @type {ModelManager} */ this.model = undefined; /** * shortcut for model * @memberof beez.manager * @name m * @type {ModelManager} */ this.m = undefined; /** * ViewManager instance * @memberof beez.manager * @name view * @type {ViewManager} */ this.view = undefined; /** * shortcut for view * @memberof beez.manager * @name v * @type {ViewManager} */ this.v = undefined; /** * ControllerManager instance * @memberof beez.manager * @name controller * @type {ControllerManager} */ this.controller = undefined; /** * shortcut for controller * @memberof beez.manager * @name c * @type {ControllerManager} */ this.c = undefined; /** * RouterManager instance * @memberof beez.manager * @name router * @type {RouterManager} */ this.router = undefined; /** * shortcut for router * @memberof beez.manager * @name r * @type {RouterManager} */ this.r = undefined; /** * CSSManager instance * @memberof beez.manager * @name css * @type {CSSManager} */ this.css = undefined; /** * ImageManager instance * @memberof beez.manager * @name image * @type {ImageManager} */ this.image = undefined; }, /** * Beez MVCR Manager Setup * * @memberof MVCR * @instance * @public * @param {Object} objs It sets up to overwrite a management class. * @return {MVCR} */ setup: function setup(objs) { if (this.setuped) { return this; } objs = objs || {}; this.setuped = true; // Initialize ModelManager if (objs.model) { this.model = objs.model; } else { var model = require('beez-mvcr/model'); this.model = new model.ModelManager('midx'); } this.m = this.model; // shortcut // Initialize ViewManager if (objs.view) { this.view = objs.view; } else { var view = require('beez-mvcr/view'); this.view = new view.ViewManager('vidx'); } this.v = this.view; // shortcut // Initialize ControllerManager if (objs.controller) { this.controller = objs.controller; } else { var controller = require('beez-mvcr/controller'); this.controller = new controller.ControllerManager(); } this.c = this.controller; // shortcut // Initialize RouterManager if (objs.router) { this.router = objs.router; } else { var router = require('beez-mvcr/router'); this.router = new router.RouterManager(); } this.r = this.router; // shortcut // Initialize CSSManager if (objs.css) { this.css = objs.css; } else { var css = require('beez-mvcr/cssmanager'); this.css = new css.CSSManager(); } // Initialize ImageManager if (objs.image) { this.image = objs.image; } else { var image = require('beez-mvcr/imagemanager'); this.image = new image.ImageManager(mconfig.image); } return this; } }; var Manager = beez.extend( 'beez.Manager', function constructor() { return this.initialize(); }, __Manager__); var manager = new Manager(); mvcr.manager = manager; beez.manager = mvcr.manager; // shortcut return beez.mvcr; });
define(function (require, exports, module) { 'use strict'; var beez = require('beez.core'); var utils = require('beez.utils'); var _ = beez.vendor._; var $ = beez.vendor.$; var logger = beez.getLogger('beez.mvcr.imagemanager'); /** * transparent-1px image data * @type {String} */ var transparentImageDataURI = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAMAAAAoyzS7AAAABlBMVEX///8AAABVwtN+AAAAAXRSTlMAQObYZgAAAA1JREFUeNoBAgD9/wAAAAIAAVMrnDAAAAAASUVORK5CYII='; var _uid = 0; var uid = function uid() { return '__beez_manager_image_uid_' + _uid++; }; /** * Class that manages multiple Image Object. re-use function of <img>. * * @class * @name ImangePool * @private * @param {int} size Pool size. Throw Error when exceeds the specified size. Setting "0", unlimited. * @throw {Error} */ var ImangePool = beez.extend( 'beez.mvcr.ImagePool', function constructor(size, options) { return this.initialize(size, options); }, { /** * Constructor * * @memberof ImangePool * @instance * @param {int} size Pool size. Throw Error when exceeds the specified size. Setting "0", unlimited. * @param {Object} options for creating image */ initialize: function initialize(size, options) { /** * for creating image * * @memberof ImangePool * @instance * @property {Object} options */ this.options = options || {}; /** * pool limit * * @memberof ImangePool * @instance * @property {int} limit */ this.limit = size; /** * The total number of generated HTMLImageElement * * @memberof ImangePool * @instance * @private */ this._total = 0; /** * HTMLImageElement total number in use. * * @memberof ImangePool * @instance * @private */ this._num_used = 0; /** * HTMLImageElement hash in use. * * @memberof ImangePool * @instance * @private */ this._using = {}; /** * Waiting for reuse HTMLImageElement * * @memberof ImangePool * @instance * @private * @return {Array} */ this._unused = []; }, /** * Generate HTMLImageElement. * * It is returned when there is recyclable HTMLImageElement. * release() is given to HTMLImageElement. * Please call release () to always While destroying HTMLImageElement. * * @memberof ImangePool * @instance * @param {Object} options for creating image * @return {HTMLImageElement} */ create: function create(options) { var elem; //options = options || this.options || {}; // default) not "Anonymous" options = options || {}; // default) not "Anonymous" if (this._unused.length > 0) { elem = this._unused.pop(); } else { if (this.limit > 0 && this._total >= this.limit) { throw new beez.Error('image pool limit exceeds!'); } elem = new Image(); elem.__beez_manager_image_uid = uid(); this._total++; } //elem.crossOrigin = options.crossOrigin ? options.crossOrigin : elem.crossOrigin; //elem.crossOrigin = options.crossOrigin ? options.crossOrigin : options.crossOrigin; if (options.crossOrigin) { elem.crossOrigin = options.crossOrigin; } else if (this.options.crossOrigin) { elem.crossOrigin = this.options.crossOrigin; } this._num_used++; this._using[elem.__beez_manager_image_uid] = elem; var self = this; /** * The HTMLImageelement waiting for reuse. * This function will be removed in the release() timing. */ elem.release = function release() { this.crossOrigin = null; // force null!! this.src = transparentImageDataURI; self._using && delete self._using[this.__beez_manager_image_uid]; self._unused && self._unused.push(this); self._num_used && self._num_used--; delete this.release; }; return elem; }, /** * It is the number of HTMLImageElement(s) during use. * * @memberof ImangePool * @instance * @returns {int} */ living: function living() { return this._num_used; }, /** * The total number of HTMLImageElement * * @memberof ImangePool * @instance * @returns {int} */ peak: function peak() { return this._total; }, /** * Waiting for reuse of HTMLImageElement * * @memberof ImangePool * @instance * @returns {int} */ waiting: function waiting() { return this._unused.length; }, /** * Disposes of the instance * * @memberof ImangePool */ dispose: function dispose() { logger.trace(this.constructor.name, 'dispose'); // release all of using images for (var id in this._using) { this._using[id].release(); } delete this._using; while (this._unused.length > 0) { var e = this._unused.pop(); delete e.__beez_manager_image_uid; } delete this._unused; delete this._num_used; delete this._total; delete this._limit; } } ); /** * Image management class. asynchronous * * @class * @name ImageManagerAsync * @private * @extends Bucks * @example * var l = new ImageManagerAsync(); * l.load('http://...').then(res, next) { * // res[0] is loaded image * }).end(); */ var ImageManagerAsync = beez.Bucks.extend( 'beez.mvcr.ImageManagerAsync', { /** * Constructor * @memberof ImageManagerAsync */ initialize: function initialize(imageManager) { this.imageManager = imageManager; }, /** * Load the image. * * @memberof ImageManagerAsync * @instance * @param {String} url * @param {Object} options for creating image * @return {Bucks} * @example * loader.loadOne('http://...').then(function onload(res, next) { * // res is a loaded-image * // next(null, ...) * }).error(function onError(err, next) { * // on error * }).end(); */ loadOne: function loadOne(url, options) { var img = this.imageManager.create(options); var self = this; return this.add(function loadTask(err, res, next) { var $img = $(img); var onLoad = function onLoad() { $img.off(); next(null, img); }; var onError = function onError(ev) { var src = img.src; $img.off(); img.release(); next(new beez.Error('error on load image. src:' + src)); }; var onAbort = function onAbort(ev) { var src = img.src; $img.off(); img.release(); next(new beez.Error('image loading aborted. src:' + src)); }; $img.on('load', onLoad); $img.on('error', onError); $img.on('abort', onAbort); // start loading var _url = self.imageManager.imageUrl(url); // replace ${ratio} img.src = _url; }); }, /** * Load the image(s). * * @memberof ImageManagerAsync * @instance * @param {String|Array} url ex) Array: ['hoge.png', 'foo.png'] * @param {Object|Array} options ex) Array: [{crossOrigin: "Anonymous"}, {crossOrigin: ""}] * @return {Bucks} ex.) {res:[HTMLImageElement, null, null, HTMLImageElement], err:[null, Error, Error, HTMLImageElement]} */ load: function load(url, options) { // param check and Array-nize if (_.isString(url)) { url = [url]; } else if (!_.isArray(url)) { throw new beez.Error('url can be String or Array of string.'); } // param check and Array-nize options = options || {}; if (!_.isArray(options)) { if (_.isObject(options)) { options = [options]; } else { throw new beez.Error('options can be Object or Array of object.'); } } // make tasks var self = this; var tasks = _.map(url, function makeTask(u, idx) { return function loadTask(err, res, next) { new ImageManagerAsync(self.imageManager) .loadOne(u, options[idx]) .end(function complete(err, res) { next(err, res[0]); }, function onError(e) { next(e); }); }; }); // parallel load return this.parallel(tasks); }, /** * dispose this ImageManagerAsync * * @memberof ImageManagerAsync * @instance * @private */ dispose: function dispose() { delete this.imageManager; } } ); /** * Image management class. synchronism * * @class * @name ImageManager * @param {Object} [options] * @param {int} [options.size] Pool size. Throw Error when exceeds the specified size. Setting "0", unlimited. */ var ImageManager = beez.extend( 'beez.mvcr.ImageManager', function constructor(options) { return this.initialize(options); }, { /** * Constructor * * @memberof ImageManager * @param {Object} options for creating image * @example * var options = { * size: 10, * pool: { * crossOrigin: 'Anonymous' * } * }; * var manager = new ImageManager(options); * * */ initialize: function initialize(options) { var size = (options && options.size) ? options.size : 0; var pool = (options && options.pool) ? options.pool : {}; this.pool = new ImangePool(size, pool); }, /** * Replaced by pixcelRatio of the URL $ {ratio} * * @memberof ImageManager */ imageUrl: function imageUrl(url) { return url.replace('${ratio}', beez.utils.pixelRatio * 10); }, /** * Generate HTMLImageElement. * * It is returned when there is recyclable HTMLImageElement. * release() is given to HTMLImageElement. * Please call release () to always While destroying HTMLImageElement. * * @memberof ImageManager * @param {Object} options for creating image * @instance */ create: function create(options) { return this.pool.create(options); }, /** * It is the number of HTMLImageElement(s) during use. * * @memberof ImageManager * @instance * @returns {int} */ living: function living() { return this.pool.living(); }, /** * The total number of HTMLImageElement * * @memberof ImageManager * @instance * @returns {int} */ peak: function peak() { return this.pool.peak(); }, /** * Waiting for reuse of HTMLImageElement * * @memberof ImageManager * @instance * @returns {int} */ waiting: function waiting() { return this.pool.waiting(); }, /** * Load the image(s). * * @memberof ImageManager * @instance * @param {String|Array} url * @param {Object|Array} options ex) Array: [{crossOrigin: "Anonymous"}, {crossOrigin: ""}] * @return {ImageManagerAsync} * @see ImageManagerAsync#load */ load: function load(url, options) { return new ImageManagerAsync(this).load(url, options); }, /** * Load the image(s). * * @memberof ImageManager * @instance * @param {String} url * @param {Object} options * @return {ImageManagerAsync} * @see ImageManagerAsync#loadOne */ loadOne: function loadOne(url, options) { return new ImageManagerAsync(this).loadOne(url, options); }, /** * dispose this ImageManagerAsync * * @memberof ImageManager * @instance * @private */ dispose: function dispose() { logger.trace(this.constructor.name, 'dispose'); this.pool.dispose(); delete this.pool; } } ); return { ImageManager: ImageManager, ImageManagerAsync: ImageManagerAsync }; });