<commit_before>frappe.ui.FilterGroup = class {
	constructor(opts) {
		$.extend(this, opts);
		this.filters = [];
		window.fltr = this;
		if (!this.filter_button) {
			this.wrapper = this.parent;
			this.wrapper.append(this.get_filter_area_template());
			this.set_filter_events();
		} else {
			this.make_popover();
		}
	}

	make_popover() {
		this.init_filter_popover();
		this.set_popover_events();
	}

	init_filter_popover() {
		this.filter_button.popover({
			content: this.get_filter_area_template(),
			template: `

			`,
			html: true,
			trigger: 'manual',
			container: 'body',
			placement: 'bottom',
			offset: '-100px 0'
		});
	}

	toggle_empty_filters(show) {
		this.wrapper &&
			this.wrapper.find('.empty-filters').toggle(show);
	}

	set_popover_events() {
		$(document.body).on('click', (e) => {
			if (this.wrapper && this.wrapper.is(':visible')) {
				if (
					$(e.target).parents('.filter-popover').length === 0
					&& $(e.target).parents('.filter-box').length === 0
					&& this.filter_button.find($(e.target)).length === 0
					&& !$(e.target).is(this.filter_button)
				) {
					this.wrapper && this.filter_button.popover('hide');
				}
			}
		});

		this.filter_button.on('click', () => {
			this.filter_button.popover('toggle');
		});

		this.filter_button.on('shown.bs.popover', (e) => {
			if (!this.wrapper) {
				this.wrapper = $('.filter-popover');
				if (this.filters && this.filters.length > 0) {
					this.toggle_empty_filters(false);
					this.add_filters_to_popover(this.filters);
				}
				this.set_filter_events();
			}
		});

		this.filter_button.on('hidden.bs.popover', (e) => {
			this.on_change();
			this.update_filters();
		});

		$(window).on('hashchange', () => {
			this.filter_button.popover('hide');
		});
	}

	add_filters_to_popover(filters) {
		filters.forEach(filter => {
			filter.parent = this.wrapper;
			filter.field = null;
			filter.make();
		});
	}

	update_filter_button() {
		const filters_applied = this.filters.length > 0;
		const button_label = filters_applied
			? this.filters.length > 1
			? __(`{0} filters`, [this.filters.length])
			: __(`{0} filter`, [this.filters.length])
			: __('Filter');

		this.filter_button
			.toggleClass('btn-default', !filters_applied)
			.toggleClass('btn-primary-light', filters_applied);

		this.filter_button.find('.filter-icon')
			.toggleClass('active', filters_applied);

		this.filter_button.find('.button-label').html(button_label);
	}

	set_filter_events() {
		this.wrapper.find('.add-filter').on('click', () => {
			this.toggle_empty_filters(false);
			this.add_filter(this.doctype, 'name');
		});

		this.wrapper.find('.clear-filters').on('click', () => {
			this.toggle_empty_filters(true);
			this.clear_filters();
		});
	}

	add_filters(filters) {
		let promises = [];

		for (const filter of filters) {
			promises.push(() => this.add_filter(...filter));
		}

		return frappe.run_serially(promises).then(() => this.update_filters());
	}

	add_filter(doctype, fieldname, condition, value, hidden) {
		if (!fieldname) return Promise.resolve();
		// adds a new filter, returns true if filter has been added

		// {}: Add in page filter by fieldname if exists ('=' => 'like')

		if (!this.validate_args(doctype, fieldname)) return false;
		const is_new_filter = arguments.length < 2;
		if (is_new_filter && this.wrapper.find('.new-filter:visible').length) {
			// only allow 1 new filter at a time!
			return Promise.resolve();
		} else {
			let args = [doctype, fieldname, condition, value, hidden];
			const promise = this.push_new_filter(args, is_new_filter);
			return (promise && promise.then) ? promise : Promise.resolve();
		}
	}

	validate_args(doctype, fieldname) {
		if (
			doctype &&
			fieldname &&
			!frappe.meta.has_field(doctype, fieldname) &&
			!frappe.model.std_fields_list.includes(fieldname)
		) {
			frappe.throw(__(`Invalid filter: "${[fieldname.bold()]}"`));
			return false;
		}
		return true;
	}

	push_new_filter(args, is_new_filter = false) {
		// args: [doctype, fieldname, condition, value]
		if (this.filter_exists(args)) return;

		// {}: Clear page filter fieldname field

		let filter = this._push_new_filter(...args);

		if (filter && filter.value) {
			// filter.setup_state(is_new_filter);
			return filter._filter_value_set; // internal promise
		}
	}

	_push_new_filter(doctype, fieldname, condition, value, hidden = false) {
		let args = {
			parent: this.wrapper,
			parent_doctype: this.doctype,
			doctype: doctype,
			fieldname: fieldname,
			condition: condition,
			value: value,
			hidden: hidden,
			on_change: (update) => {
				if (update) this.update_filters();
				this.on_change();
			},
			filter_items: (doctype, fieldname) => {
				return !this.filter_exists([doctype, fieldname]);
			},
			base_list: this.base_list,
		};
		let filter = new frappe.ui.Filter(args);
		this.filters.push(filter);
		return filter;
	}

	filter_exists(filter_value) {
		// filter_value of form: [doctype, fieldname, condition, value]
		let exists = false;
		this.filters
			.filter((f) => f.field)
			.map((f) => {
				let f_value = f.get_value();
				if (filter_value.length === 2) {
					exists =
						filter_value[0] === f_value[0] && filter_value[1] === f_value[1];
					return;
				}

				let value = filter_value[3];
				let equal = frappe.utils.arrays_equal;

				if (
					equal(f_value.slice(0, 4), filter_value.slice(0, 4)) ||
					(Array.isArray(value) && equal(value, f_value[3]))
				) {
					exists = true;
				}
			});
		return exists;
	}

	get_filters() {
		return this.filters
			.filter((f) => f.field)
			.map((f) => {
				return f.get_value();
			});
		// {}: this.list.update_standard_filters(values);
	}

	update_filters() {
		this.filters = this.filters.filter((f) => f.field); // remove hidden filters
		this.update_filter_button();
		this.filters.length === 0 &&
			this.toggle_empty_filters(true);
	}

	clear_filters() {
		this.filters.map((f) => f.remove(true));
		// {}: Clear page filters, .date-range-picker (called list run())
		this.filters = [];
	}

	get_filter(fieldname) {
		return this.filters.filter((f) => {
			return f.field && f.field.df.fieldname == fieldname;
		})[0];
	}

	get_filter_area_template() {
		return $(`

					No filters selected

						${__("+ Add a Filter")}

					<button class="btn btn-secondary-dark btn-xs clear-filters">
						${__("Clear Filters")}
					</button>

`
		);
	}

	get_filters_as_object() {
		let filters = this.get_filters().reduce((acc, filter) => {
			return Object.assign(acc, {
				[filter[1]]: [filter[2], filter[3]],
			});
		}, {});
		return filters;
	}

	add_filters_to_filter_group(filters) {
		filters.forEach((filter) => {
			this.add_filter(filter[0], filter[1], filter[2], filter[3]);
		});
	}

	add(filters, refresh = true) {
		if (!filters || (Array.isArray(filters) && filters.length === 0))
			return Promise.resolve();

		if (typeof filters[0] === "string") {
			// passed in the format of doctype, field, condition, value
			const filter = Array.from(arguments);
			filters = [filter];
		}

		filters = filters.filter((f) => {
			return !this.exists(f);
		});

		const { non_standard_filters, promise } = this.set_standard_filter(
			filters
		);

		return promise
			.then(() => {
				return (
					non_standard_filters.length > 0 &&
					this.filter_list.add_filters(non_standard_filters)
				);
			})
			.then(() => {
				refresh && this.list_view.refresh();
			});
	}
};
<commit_msg>fix: Do not hide filter popover on date selection<commit_after>frappe.ui.FilterGroup = class {
	constructor(opts) {
		$.extend(this, opts);
		this.filters = [];
		window.fltr = this;
		if (!this.filter_button) {
			this.wrapper = this.parent;
			this.wrapper.append(this.get_filter_area_template());
			this.set_filter_events();
		} else {
			this.make_popover();
		}
	}

	make_popover() {
		this.init_filter_popover();
		this.set_popover_events();
	}

	init_filter_popover() {
		this.filter_button.popover({
			content: this.get_filter_area_template(),
			template: `

			`,
			html: true,
			trigger: 'manual',
			container: 'body',
			placement: 'bottom',
			offset: '-100px 0'
		});
	}

	toggle_empty_filters(show) {
		this.wrapper &&
			this.wrapper.find('.empty-filters').toggle(show);
	}

	set_popover_events() {
		$(document.body).on('click', (e) => {
			if (this.wrapper && this.wrapper.is(':visible')) {
				if (
					$(e.target).parents('.filter-popover').length === 0
					&& $(e.target).parents('.filter-box').length === 0
					&& this.filter_button.find($(e.target)).length === 0
					&& !$(e.target).is(this.filter_button)
					&& !$(e.target).is('.datepicker--cell')
				) {
					this.wrapper && this.filter_button.popover('hide');
				}
			}
		});

		this.filter_button.on('click', () => {
			this.filter_button.popover('toggle');
		});

		this.filter_button.on('shown.bs.popover', (e) => {
			if (!this.wrapper) {
				this.wrapper = $('.filter-popover');
				if (this.filters && this.filters.length > 0) {
					this.toggle_empty_filters(false);
					this.add_filters_to_popover(this.filters);
				}
				this.set_filter_events();
			}
		});

		this.filter_button.on('hidden.bs.popover', (e) => {
			this.on_change();
			this.update_filters();
		});

		$(window).on('hashchange', () => {
			this.filter_button.popover('hide');
		});
	}

	add_filters_to_popover(filters) {
		filters.forEach(filter => {
			filter.parent = this.wrapper;
			filter.field = null;
			filter.make();
		});
	}

	update_filter_button() {
		const filters_applied = this.filters.length > 0;
		const button_label = filters_applied
			? this.filters.length > 1
			? __(`{0} filters`, [this.filters.length])
			: __(`{0} filter`, [this.filters.length])
			: __('Filter');

		this.filter_button
			.toggleClass('btn-default', !filters_applied)
			.toggleClass('btn-primary-light', filters_applied);

		this.filter_button.find('.filter-icon')
			.toggleClass('active', filters_applied);

		this.filter_button.find('.button-label').html(button_label);
	}

	set_filter_events() {
		this.wrapper.find('.add-filter').on('click', () => {
			this.toggle_empty_filters(false);
			this.add_filter(this.doctype, 'name');
		});

		this.wrapper.find('.clear-filters').on('click', () => {
			this.toggle_empty_filters(true);
			this.clear_filters();
		});
	}

	add_filters(filters) {
		let promises = [];

		for (const filter of filters) {
			promises.push(() => this.add_filter(...filter));
		}

		return frappe.run_serially(promises).then(() => this.update_filters());
	}

	add_filter(doctype, fieldname, condition, value, hidden) {
		if (!fieldname) return Promise.resolve();
		// adds a new filter, returns true if filter has been added

		// {}: Add in page filter by fieldname if exists ('=' => 'like')

		if (!this.validate_args(doctype, fieldname)) return false;
		const is_new_filter = arguments.length < 2;
		if (is_new_filter && this.wrapper.find('.new-filter:visible').length) {
			// only allow 1 new filter at a time!
			return Promise.resolve();
		} else {
			let args = [doctype, fieldname, condition, value, hidden];
			const promise = this.push_new_filter(args, is_new_filter);
			return (promise && promise.then) ? promise : Promise.resolve();
		}
	}

	validate_args(doctype, fieldname) {
		if (
			doctype &&
			fieldname &&
			!frappe.meta.has_field(doctype, fieldname) &&
			!frappe.model.std_fields_list.includes(fieldname)
		) {
			frappe.throw(__(`Invalid filter: "${[fieldname.bold()]}"`));
			return false;
		}
		return true;
	}

	push_new_filter(args, is_new_filter = false) {
		// args: [doctype, fieldname, condition, value]
		if (this.filter_exists(args)) return;

		// {}: Clear page filter fieldname field

		let filter = this._push_new_filter(...args);

		if (filter && filter.value) {
			// filter.setup_state(is_new_filter);
			return filter._filter_value_set; // internal promise
		}
	}

	_push_new_filter(doctype, fieldname, condition, value, hidden = false) {
		let args = {
			parent: this.wrapper,
			parent_doctype: this.doctype,
			doctype: doctype,
			fieldname: fieldname,
			condition: condition,
			value: value,
			hidden: hidden,
			on_change: (update) => {
				if (update) this.update_filters();
				this.on_change();
			},
			filter_items: (doctype, fieldname) => {
				return !this.filter_exists([doctype, fieldname]);
			},
			base_list: this.base_list,
		};
		let filter = new frappe.ui.Filter(args);
		this.filters.push(filter);
		return filter;
	}

	filter_exists(filter_value) {
		// filter_value of form: [doctype, fieldname, condition, value]
		let exists = false;
		this.filters
			.filter((f) => f.field)
			.map((f) => {
				let f_value = f.get_value();
				if (filter_value.length === 2) {
					exists =
						filter_value[0] === f_value[0] && filter_value[1] === f_value[1];
					return;
				}

				let value = filter_value[3];
				let equal = frappe.utils.arrays_equal;

				if (
					equal(f_value.slice(0, 4), filter_value.slice(0, 4)) ||
					(Array.isArray(value) && equal(value, f_value[3]))
				) {
					exists = true;
				}
			});
		return exists;
	}

	get_filters() {
		return this.filters
			.filter((f) => f.field)
			.map((f) => {
				return f.get_value();
			});
		// {}: this.list.update_standard_filters(values);
	}

	update_filters() {
		this.filters = this.filters.filter((f) => f.field); // remove hidden filters
		this.update_filter_button();
		this.filters.length === 0 &&
			this.toggle_empty_filters(true);
	}

	clear_filters() {
		this.filters.map((f) => f.remove(true));
		// {}: Clear page filters, .date-range-picker (called list run())
		this.filters = [];
	}

	get_filter(fieldname) {
		return this.filters.filter((f) => {
			return f.field && f.field.df.fieldname == fieldname;
		})[0];
	}

	get_filter_area_template() {
		return $(`

					No filters selected

						${__("+ Add a Filter")}

					<button class="btn btn-secondary-dark btn-xs clear-filters">
						${__("Clear Filters")}
					</button>

`
		);
	}

	get_filters_as_object() {
		let filters = this.get_filters().reduce((acc, filter) => {
			return Object.assign(acc, {
				[filter[1]]: [filter[2], filter[3]],
			});
		}, {});
		return filters;
	}

	add_filters_to_filter_group(filters) {
		filters.forEach((filter) => {
			this.add_filter(filter[0], filter[1], filter[2], filter[3]);
		});
	}

	add(filters, refresh = true) {
		if (!filters || (Array.isArray(filters) && filters.length === 0))
			return Promise.resolve();

		if (typeof filters[0] === "string") {
			// passed in the format of doctype, field, condition, value
			const filter = Array.from(arguments);
			filters = [filter];
		}

		filters = filters.filter((f) => {
			return !this.exists(f);
		});

		const { non_standard_filters, promise } = this.set_standard_filter(
			filters
		);

		return promise
			.then(() => {
				return (
					non_standard_filters.length > 0 &&
					this.filter_list.add_filters(non_standard_filters)
				);
			})
			.then(() => {
				refresh && this.list_view.refresh();
			});
	}
};
<|endoftext|>


<commit_before>
const defaultOptions = {
    graceful: true
};

export default function sync(animationName, options = {}) {
    const opts = {
        ...defaultOptions,
        ...options
    };

    const elements = new Set();
    let eventTime;
    let lastInterationTS = now();
    let interationDuration = 0;

    function animationStart(event) {
        if (event.animationName === animationName) {
            const el = event.target;

            if (opts.graceful && !elements.has(el) && interationDuration !== 0) {
                gracefulStart(el, interationDuration, lastInterationTS);
            }

            elements.add(el);
        }
    }

    function animationIteration(event) {
        if (event.animationName === animationName) {
            elements.add(event.target);

            requestAnimationFrame(frameTime => {
                if (frameTime !== eventTime) {
                    interationDuration = now() - lastInterationTS;
                    lastInterationTS = now();
                    restart(elements);
                }

                eventTime = frameTime;
            });
        }
    }

    window.addEventListener('animationstart', animationStart, true);
    window.addEventListener('animationiteration', animationIteration, true);

    return {
        free() {
            window.removeEventListener('animationstart', animationStart);
            window.removeEventListener('animationiteration', animationIteration);

            this.start();
            elements.clear();
        },

        start() {
            elements.forEach(el => {
                if (validate(elements, el)) {
                    el.style.removeProperty('animation');
                }
            });
        },

        stop() {
            elements.forEach(el => {
                if (validate(elements, el)) {
                    el.style.setProperty('animation', 'none');
                }
            });
        },

        pause() {
            elements.forEach(el => {
                if (validate(elements, el)) {
                    el.style.setProperty('animation-play-state', 'paused');
                }
            });
        }
    };
}

function restart(elements) {
    elements.forEach(el => {
        if (window.getComputedStyle(el).animationPlayState !== 'paused') {
            if (validate(elements, el)) {
                el.style.setProperty('animation', 'none');
            }
        }
    });

    requestAnimationFrame(() => {
        elements.forEach(el => {
            if (window.getComputedStyle(el).animationPlayState !== 'paused') {
                if (validate(elements, el)) {
                    el.style.removeProperty('animation');
                }
            }
        });
    });
}

function gracefulStart(el, interationDuration, lastInterationTS) {
    const remaining = interationDuration - (now() - lastInterationTS);
    console.log(interationDuration, remaining);
    el.style.setProperty('animation-duration', remaining);
}

function now() {
    return (new Date()).getTime();
}

function validate(elements, el) {
    const isValid = document.body.contains(el);
    if (!isValid) {
        elements.delete(el);
    }
    return isValid;
}
<commit_msg>Remove console.log<commit_after>
const defaultOptions = {
    graceful: true
};

export default function sync(animationName, options = {}) {
    const opts = {
        ...defaultOptions,
        ...options
    };

    const elements = new Set();
    let eventTime;
    let lastInterationTS = now();
    let interationDuration = 0;

    function animationStart(event) {
        if (event.animationName === animationName) {
            const el = event.target;

            if (opts.graceful && !elements.has(el) && interationDuration !== 0) {
                gracefulStart(el, interationDuration, lastInterationTS);
            }

            elements.add(el);
        }
    }

    function animationIteration(event) {
        if (event.animationName === animationName) {
            elements.add(event.target);

            requestAnimationFrame(frameTime => {
                if (frameTime !== eventTime) {
                    interationDuration = now() - lastInterationTS;
                    lastInterationTS = now();
                    restart(elements);
                }

                eventTime = frameTime;
            });
        }
    }

    window.addEventListener('animationstart', animationStart, true);
    window.addEventListener('animationiteration', animationIteration, true);

    return {
        free() {
            window.removeEventListener('animationstart', animationStart);
            window.removeEventListener('animationiteration', animationIteration);

            this.start();
            elements.clear();
        },

        start() {
            elements.forEach(el => {
                if (validate(elements, el)) {
                    el.style.removeProperty('animation');
                }
            });
        },

        stop() {
            elements.forEach(el => {
                if (validate(elements, el)) {
                    el.style.setProperty('animation', 'none');
                }
            });
        },

        pause() {
            elements.forEach(el => {
                if (validate(elements, el)) {
                    el.style.setProperty('animation-play-state', 'paused');
                }
            });
        }
    };
}

function restart(elements) {
    elements.forEach(el => {
        if (window.getComputedStyle(el).animationPlayState !== 'paused') {
            if (validate(elements, el)) {
                el.style.setProperty('animation', 'none');
            }
        }
    });

    requestAnimationFrame(() => {
        elements.forEach(el => {
            if (window.getComputedStyle(el).animationPlayState !== 'paused') {
                if (validate(elements, el)) {
                    el.style.removeProperty('animation');
                }
            }
        });
    });
}

function gracefulStart(el, interationDuration, lastInterationTS) {
    const remaining = interationDuration - (now() - lastInterationTS);
    el.style.setProperty('animation-duration', remaining);
}

function now() {
    return (new Date()).getTime();
}

function validate(elements, el) {
    const isValid = document.body.contains(el);
    if (!isValid) {
        elements.delete(el);
    }
    return isValid;
}
<|endoftext|>


<commit_before>'use strict';

(function(window, document, $, module, exports, require, swal, Qiniu, QiniuConfig){
  let Loader = require('component/common/loader');
  let data = {};
  let _id = null;
  let $element = $;

  $('[name=modifyReplyBtn]').click(function() {
    $element = $(this).parents('.panel');
    _id = $element.data('id');
    $.ajax({
      type: 'GET',
      url: '/api/admin/subscribeReply/' + _id,
      data: 'json',
      contentType: 'application/json',
      success: function(resData) {
        data = resData;
        render();
        $('[name=modifyReplyBtn]').prop('disabled', true);
        $('[name=deleteReplyBtn]').prop('disabled', true);
      }
    });
  });

  function render() {
    $element.html(`

        等待 <input type="number" name='waitSeconds' min="0" class="form-control" autocomplete="off" style="width: 100px; display: inline-block;" value="${data.waitSeconds}"> 分钟后回复
        <button class="btn btn-xs btn-default pull-right" name="cancelBtn">取消</button>
        <button class="btn btn-xs btn-green pull-right mr-sm" name="saveReplyBtn">保存</button>
        <button class="btn btn-xs btn-primary pull-right mr-sm" name="addImageBtn">增加图片</button>
        <button class="btn btn-xs btn-primary pull-right mr-sm" name="addTextBtn">增加文本</button>

          ${data.messages ? data.messages.map((message) => {
            if(message.type === 'text') {
              return `

                  ${message.content}

                    <button class="btn btn-danger btn-xs pull-right" name="deleteMessageBtn">删除</button>
                    <button class="btn btn-default btn-xs pull-right mr-sm" name="backwardMessageBtn">下移</button>
                    <button class="btn btn-default btn-xs pull-right mr-sm" name="forwardMessageBtn">上移</button>

`
            }
            if(message.type === 'image') {
              return `

                    <button class="btn btn-danger btn-xs pull-right" name="deleteMessageBtn">删除</button>
                    <button class="btn btn-default btn-xs pull-right mr-sm" name="backwardMessageBtn">下移</button>
                    <button class="btn btn-default btn-xs pull-right mr-sm" name="forwardMessageBtn">上移</button>

`
            }
          }).join('') : ''}

    `);
    bind($element);
  }

  function bind($element) {
    require('component/common/img_preview')();

    $element.find('[name=addTextBtn]').unbind().on('click', function(e) {
      $(this).parents('.panel').find('.message-bubble-list').append(`

          <textarea class="form-control" name="message" placeholder="请输入消息内容"></textarea>

            <button class="btn btn-default btn-xs pull-right" name="confirmTextBtn">确定</button>
            <button class="btn btn-default btn-xs pull-right mr-sm" name="cancelBtn">取消</button>

      `);
      // 禁止无关按钮触发
      disableBtnOnEditing();
      $element.find('[name=confirmTextBtn]').unbind().on('click', function() {
        let text = $element.find('textarea[name=message]').val();
        data.messages.push({
          type: 'text',
          content: text
        });
        render();
      });
      $element.find('[name=cancelBtn]').unbind().on('click', function() {
        render();
      });
    });
    $element.find('[name=addImageBtn]').unbind().on('click', function(e) {
      $(this).parents('.panel').find('.message-bubble-list').append(`

          <button class="btn btn-default btn-xs" name="uploadImage">上传新图片</button>
          <button class="btn btn-default btn-xs" name="chooseImage">选择已有图片</button>
          <button class="btn btn-default btn-xs pull-right mr-sm" name="cancelBtn">取消</button>

      `);
      // 禁止无关按钮触发
      disableBtnOnEditing();

      $element.find('[name=uploadImage]').unbind().on('click', function() {
        $('body').append($('#create-tpl').html());
        $('#create').modal({backdrop: 'static', keyboard: false});
        $('[name=submitBtn]').prop('disabled', true);

        $('input[type=file]').on("change", function (e) {
          let file = e.currentTarget.files[0];
          if(file) {
            if(file.size > 2000000) {
              alert('图片文件大小不得超过2M');
              $('[name=submitBtn]').prop('disabled', true);
            } else {
              console.log(file);
              $('[name=submitBtn]').prop('disabled', false);
              $('[name=uploadFilePath]').text(file.name);
            }
          }
        });

        $('#image-upload-btn').unbind().on('click', function(e) {
          $('input[type=file]').trigger('click');
        })

        $('#create #image-form').on('submit', function (e) {
          if (e.isDefaultPrevented()) {
          } else {
            e.preventDefault();
            let formData = new FormData();
            formData.append('type', 'image');
            formData.append('file', $('input[type=file]')[0].files[0]);
            Loader.show();
            $.ajax({
              url : '/api/admin/material',
              type : 'POST',
              data : formData,
              cache: false,
              contentType: false,
              processData: false,
              success : function(resData) {
                Loader.hide();
                console.log(resData);
                if (resData.error) {
                  if (typeof resData.error.message === 'object') {
                    resData.error.message = resData.error.message.join('\n');
                  }
                  return swal('错误', resData.error.message, 'error');
                }
                swal({
                    title : "图片上传成功",
                    type : "success"
                  },
                  function () {
                    $('#create').modal('hide');
                    let mediaId = resData.media_id;
                    data.messages.push({
                      type: 'image',
                      mediaId: mediaId
                    });
                    render();
                  });
              }
            });
          }
        });
        $('#create').on('hidden.bs.modal', function () {
          $('#create').remove();
        });
      });

      let imgSelector = require('component/common/img_selector');
      imgSelector('[name=chooseImage]', function(mediaId) {
        data.messages.push({
          type: 'image',
          mediaId: mediaId
        });
        render();
      });

      $element.find('[name=cancelBtn]').unbind().on('click', function() {
        render();
      });
    });

    $element.find('[name=forwardMessageBtn]').unbind().on('click', function(e) {
      let messageIndex = $(this).parents('.message-bubble-list').find('li').index($(this).parents('li'));
      moveMessage(messageIndex, -1);
    });
    $element.find('[name=backwardMessageBtn]').unbind().on('click', function(e) {
      let messageIndex = $(this).parents('.message-bubble-list').find('li').index($(this).parents('li'));
      moveMessage(messageIndex, 1);
    });
    $element.find('[name=deleteMessageBtn]').unbind().on('click', function(e) {
      let messageIndex = $(this).parents('.message-bubble-list').find('li').index($(this).parents('li'));
      deleteMessage(messageIndex);
    });
    $element.find('[name=saveReplyBtn]').unbind().on('click', function() {
      let waitSeconds = parseInt($element.find('input[name=waitSeconds]').val() || 0);
      $.ajax({
        url : '/api/admin/subscribeReply/' + _id,
        type : 'PUT',
        data : JSON.stringify({
          waitSeconds: waitSeconds,
          messages: data.messages
        }),
        dataType: 'json',
        contentType: 'application/json',
        success : function(data) {
          Loader.hide();
          console.log(data);
          if (data.error) {
            if (typeof data.error.message === 'object') {
              data.error.message = data.error.message.join('\n');
            }
            return swal('错误', data.error.message, 'error');
          }
          swal({
              title : "回复消息组修改成功",
              type : "success"
            },
            function () {
              $('#modify').modal('hide');
              location.reload();
            });
        }
      });
      render();
    });
    $element.find('[name=cancelBtn]').unbind().on('click', function() {
      location.reload();
    });
  }

  function disableBtnOnEditing() {
    $element.find('[name=addTextBtn]').prop('disabled', true);
    $element.find('[name=addImageBtn]').prop('disabled', true);
    $element.find('[name=forwardMessageBtn]').prop('disabled', true);
    $element.find('[name=backwardMessageBtn]').prop('disabled', true);
    $element.find('[name=modifyMessageBtn]').prop('disabled', true);
    $element.find('[name=deleteMessageBtn]').prop('disabled', true);
    $element.find('[name=previewImageBtn]').prop('disabled', true);
  }

  function moveMessage(subIndex, offset) {
    let messageGroup = data.messages;
    let toIndex = subIndex + offset;
    (toIndex < 0) && (toIndex = 0);
    (toIndex > messageGroup.length-1) && (toIndex = messageGroup.length-1);
    _arrayMove(data.messages, subIndex, toIndex);
    render();
  }

  function deleteMessage(subIndex) {
    data.messages.splice(subIndex, 1);
    render();
  }

  function _arrayMove(arr, fromIndex, toIndex) {
    var element = arr[fromIndex];
    arr.splice(fromIndex, 1);
    arr.splice(toIndex, 0, element);
  }

})(window, document, window['jQuery'], module, exports, require, window['swal'], window['Qiniu'], window['QiniuConfig']);<commit_msg>fix(subscribeReply): 分钟 => 秒<commit_after>'use strict';

(function(window, document, $, module, exports, require, swal, Qiniu, QiniuConfig){
  let Loader = require('component/common/loader');
  let data = {};
  let _id = null;
  let $element = $;

  $('[name=modifyReplyBtn]').click(function() {
    $element = $(this).parents('.panel');
    _id = $element.data('id');
    $.ajax({
      type: 'GET',
      url: '/api/admin/subscribeReply/' + _id,
      data: 'json',
      contentType: 'application/json',
      success: function(resData) {
        data = resData;
        render();
        $('[name=modifyReplyBtn]').prop('disabled', true);
        $('[name=deleteReplyBtn]').prop('disabled', true);
      }
    });
  });

  function render() {
    $element.html(`

        等待 <input type="number" name='waitSeconds' min="0" class="form-control" autocomplete="off" style="width: 100px; display: inline-block;" value="${data.waitSeconds}"> 秒后回复
        <button class="btn btn-xs btn-default pull-right" name="cancelBtn">取消</button>
        <button class="btn btn-xs btn-green pull-right mr-sm" name="saveReplyBtn">保存</button>
        <button class="btn btn-xs btn-primary pull-right mr-sm" name="addImageBtn">增加图片</button>
        <button class="btn btn-xs btn-primary pull-right mr-sm" name="addTextBtn">增加文本</button>

          ${data.messages ? data.messages.map((message) => {
            if(message.type === 'text') {
              return `

                  ${message.content}

                    <button class="btn btn-danger btn-xs pull-right" name="deleteMessageBtn">删除</button>
                    <button class="btn btn-default btn-xs pull-right mr-sm" name="backwardMessageBtn">下移</button>
                    <button class="btn btn-default btn-xs pull-right mr-sm" name="forwardMessageBtn">上移</button>

`
            }
            if(message.type === 'image') {
              return `

                    <button class="btn btn-danger btn-xs pull-right" name="deleteMessageBtn">删除</button>
                    <button class="btn btn-default btn-xs pull-right mr-sm" name="backwardMessageBtn">下移</button>
                    <button class="btn btn-default btn-xs pull-right mr-sm" name="forwardMessageBtn">上移</button>

`
            }
          }).join('') : ''}

    `);
    bind($element);
  }

  function bind($element) {
    require('component/common/img_preview')();

    $element.find('[name=addTextBtn]').unbind().on('click', function(e) {
      $(this).parents('.panel').find('.message-bubble-list').append(`

          <textarea class="form-control" name="message" placeholder="请输入消息内容"></textarea>

            <button class="btn btn-default btn-xs pull-right" name="confirmTextBtn">确定</button>
            <button class="btn btn-default btn-xs pull-right mr-sm" name="cancelBtn">取消</button>

      `);
      // 禁止无关按钮触发
      disableBtnOnEditing();
      $element.find('[name=confirmTextBtn]').unbind().on('click', function() {
        let text = $element.find('textarea[name=message]').val();
        data.messages.push({
          type: 'text',
          content: text
        });
        render();
      });
      $element.find('[name=cancelBtn]').unbind().on('click', function() {
        render();
      });
    });
    $element.find('[name=addImageBtn]').unbind().on('click', function(e) {
      $(this).parents('.panel').find('.message-bubble-list').append(`

          <button class="btn btn-default btn-xs" name="uploadImage">上传新图片</button>
          <button class="btn btn-default btn-xs" name="chooseImage">选择已有图片</button>
          <button class="btn btn-default btn-xs pull-right mr-sm" name="cancelBtn">取消</button>

      `);
      // 禁止无关按钮触发
      disableBtnOnEditing();

      $element.find('[name=uploadImage]').unbind().on('click', function() {
        $('body').append($('#create-tpl').html());
        $('#create').modal({backdrop: 'static', keyboard: false});
        $('[name=submitBtn]').prop('disabled', true);

        $('input[type=file]').on("change", function (e) {
          let file = e.currentTarget.files[0];
          if(file) {
            if(file.size > 2000000) {
              alert('图片文件大小不得超过2M');
              $('[name=submitBtn]').prop('disabled', true);
            } else {
              console.log(file);
              $('[name=submitBtn]').prop('disabled', false);
              $('[name=uploadFilePath]').text(file.name);
            }
          }
        });

        $('#image-upload-btn').unbind().on('click', function(e) {
          $('input[type=file]').trigger('click');
        })

        $('#create #image-form').on('submit', function (e) {
          if (e.isDefaultPrevented()) {
          } else {
            e.preventDefault();
            let formData = new FormData();
            formData.append('type', 'image');
            formData.append('file', $('input[type=file]')[0].files[0]);
            Loader.show();
            $.ajax({
              url : '/api/admin/material',
              type : 'POST',
              data : formData,
              cache: false,
              contentType: false,
              processData: false,
              success : function(resData) {
                Loader.hide();
                console.log(resData);
                if (resData.error) {
                  if (typeof resData.error.message === 'object') {
                    resData.error.message = resData.error.message.join('\n');
                  }
                  return swal('错误', resData.error.message, 'error');
                }
                swal({
                    title : "图片上传成功",
                    type : "success"
                  },
                  function () {
                    $('#create').modal('hide');
                    let mediaId = resData.media_id;
                    data.messages.push({
                      type: 'image',
                      mediaId: mediaId
                    });
                    render();
                  });
              }
            });
          }
        });
        $('#create').on('hidden.bs.modal', function () {
          $('#create').remove();
        });
      });

      let imgSelector = require('component/common/img_selector');
      imgSelector('[name=chooseImage]', function(mediaId) {
        data.messages.push({
          type: 'image',
          mediaId: mediaId
        });
        render();
      });

      $element.find('[name=cancelBtn]').unbind().on('click', function() {
        render();
      });
    });

    $element.find('[name=forwardMessageBtn]').unbind().on('click', function(e) {
      let messageIndex = $(this).parents('.message-bubble-list').find('li').index($(this).parents('li'));
      moveMessage(messageIndex, -1);
    });
    $element.find('[name=backwardMessageBtn]').unbind().on('click', function(e) {
      let messageIndex = $(this).parents('.message-bubble-list').find('li').index($(this).parents('li'));
      moveMessage(messageIndex, 1);
    });
    $element.find('[name=deleteMessageBtn]').unbind().on('click', function(e) {
      let messageIndex = $(this).parents('.message-bubble-list').find('li').index($(this).parents('li'));
      deleteMessage(messageIndex);
    });
    $element.find('[name=saveReplyBtn]').unbind().on('click', function() {
      let waitSeconds = parseInt($element.find('input[name=waitSeconds]').val() || 0);
      $.ajax({
        url : '/api/admin/subscribeReply/' + _id,
        type : 'PUT',
        data : JSON.stringify({
          waitSeconds: waitSeconds,
          messages: data.messages
        }),
        dataType: 'json',
        contentType: 'application/json',
        success : function(data) {
          Loader.hide();
          console.log(data);
          if (data.error) {
            if (typeof data.error.message === 'object') {
              data.error.message = data.error.message.join('\n');
            }
            return swal('错误', data.error.message, 'error');
          }
          swal({
              title : "回复消息组修改成功",
              type : "success"
            },
            function () {
              $('#modify').modal('hide');
              location.reload();
            });
        }
      });
      render();
    });
    $element.find('[name=cancelBtn]').unbind().on('click', function() {
      location.reload();
    });
  }

  function disableBtnOnEditing() {
    $element.find('[name=addTextBtn]').prop('disabled', true);
    $element.find('[name=addImageBtn]').prop('disabled', true);
    $element.find('[name=forwardMessageBtn]').prop('disabled', true);
    $element.find('[name=backwardMessageBtn]').prop('disabled', true);
    $element.find('[name=modifyMessageBtn]').prop('disabled', true);
    $element.find('[name=deleteMessageBtn]').prop('disabled', true);
    $element.find('[name=previewImageBtn]').prop('disabled', true);
  }

  function moveMessage(subIndex, offset) {
    let messageGroup = data.messages;
    let toIndex = subIndex + offset;
    (toIndex < 0) && (toIndex = 0);
    (toIndex > messageGroup.length-1) && (toIndex = messageGroup.length-1);
    _arrayMove(data.messages, subIndex, toIndex);
    render();
  }

  function deleteMessage(subIndex) {
    data.messages.splice(subIndex, 1);
    render();
  }

  function _arrayMove(arr, fromIndex, toIndex) {
    var element = arr[fromIndex];
    arr.splice(fromIndex, 1);
    arr.splice(toIndex, 0, element);
  }

})(window, document, window['jQuery'], module, exports, require, window['swal'], window['Qiniu'], window['QiniuConfig']);<|endoftext|>


<commit_before>import riot from 'riot';

riot.tag('todo-app',

  `
Todos

   <todo-form store="{opts.store}"></todo-form>
   <todo-list store="{opts.store}"></todo-list>

     Want a second fully synchronized list? Just declare another list component:
     no code required, no events to wire up!

   <todo-list store="{opts.store}"></todo-list>`,

  function(opts) {
    let dispatcher = this.opts.store.dispatcher;
    this.on('mount', () => dispatcher.trigger(dispatcher.INIT_TODOS));
  }

);

riot.tag('todo-form',

  `<form onsubmit="{add}">
     <input name="input" type="text" placeholder="New Todo" autofocus="true">
     <input type="submit" value="Add Todo">
   </form>
   <button onclick="{clear}">Clear Completed</button>`,

  function(opts) {
    let store = this.opts.store;
    let dispatcher = store.dispatcher;

    this.add = (e) => {
      if (this.input.value) {
        dispatcher.trigger(dispatcher.ADD_TODO, {title: this.input.value, done: false});
        this.input.value = ''
      }
    };

    this.clear = (e) => {
      dispatcher.trigger(dispatcher.CLEAR_TODOS);
    };
  }

);

riot.tag('todo-list',

  `

       <todo-item store="{parent.opts.store}" todo="{item}">

`,

  function(opts) {
    let store = this.opts.store;
    store.on(store.CHANGED_EVENT, () => this.update());
  }

);

riot.tag('todo-item',

  `
     {opts.todo.title}
   `,

  function(opts) {
    let dispatcher = this.opts.store.dispatcher;

    this.toggle = () => {
      dispatcher.trigger(dispatcher.TOGGLE_TODO, opts.todo);
    }
  }

);
<commit_msg>Proptery name refactor.<commit_after>import riot from 'riot';

riot.tag('todo-app',

  `
Todos

   <todo-form store="{opts.store}"></todo-form>
   <todo-list store="{opts.store}"></todo-list>

     Want a second fully synchronized list? Just declare another list component:
     no code required, no events to wire up!

   <todo-list store="{opts.store}"></todo-list>`,

  function(opts) {
    let dispatcher = this.opts.store.dispatcher;
    this.on('mount', () => dispatcher.trigger(dispatcher.INIT_TODOS));
  }

);

riot.tag('todo-form',

  `<form onsubmit="{add}">
     <input name="input" type="text" placeholder="New Todo" autofocus="true">
     <input type="submit" value="Add Todo">
   </form>
   <button onclick="{clear}">Clear Completed</button>`,

  function(opts) {
    let store = this.opts.store;
    let dispatcher = store.dispatcher;

    this.add = (e) => {
      if (this.input.value) {
        dispatcher.trigger(dispatcher.ADD_TODO, {title: this.input.value, done: false});
        this.input.value = ''
      }
    };

    this.clear = (e) => {
      dispatcher.trigger(dispatcher.CLEAR_TODOS);
    };
  }

);

riot.tag('todo-list',

  `

       <todo-item store="{parent.opts.store}" todo="{todo}">

`,

  function(opts) {
    let store = this.opts.store;
    store.on(store.CHANGED_EVENT, () => this.update());
  }

);

riot.tag('todo-item',

  `
     {opts.todo.title}
   `,

  function(opts) {
    let dispatcher = this.opts.store.dispatcher;

    this.toggle = () => {
      dispatcher.trigger(dispatcher.TOGGLE_TODO, opts.todo);
    }
  }

);
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2011-2013, Yahoo! Inc.  All rights reserved.
 * Copyrights licensed under the New BSD License.
 * See the accompanying LICENSE file for terms.
 */

/*jslint anon:true, sloppy:true, nomen:true, node:true*/
/*global YUI*/

/*
 * Baseline Mojito client testing harness.
 */
YUI.add('mojito', function(Y, NAME) {

    // TODO: why does need to be in sync with autoload/mojito.common.js
    // why don't we just attach that to every test?

    Y.namespace('mojito');
    Y.namespace('mojito.trans');
    Y.namespace('mojito.actions');
    Y.namespace('mojito.binders');
    Y.namespace('mojito.controllers');
    Y.namespace('mojito.models');
    Y.namespace('mojito.addons');
    Y.namespace('mojito.addons.ac');
    Y.namespace('mojito.addons.viewEngines');
    // HookSystem::StartBlock
    Y.mojito.hooks = {
        hook: function () {},
        registerHook: function () {}
    };
    // HookSystem::EndBlock

    // this is a facade for the real implementation from mojito-perf module
    // that will have to be plugged manually to get the metrics in the
    // console or a log file.
    Y.mojito.perf = {
        timeline: function () {
            return {
                done: function () {}
            };
        },
        mark: function () {}
    };

    // internal mojito framework cache (this is probably legacy)
    YUI.namespace('_mojito._cache');

    // setting the stage for all data-scopes implementation
    YUI.namespace('Env.mojito');

});

/* AC ADDONS */
YUI.add('mojito-analytics-addon', function(Y, NAME) {});
YUI.add('mojito-assets-addon', function(Y, NAME) {});
YUI.add('mojito-carrier-addon', function(Y, NAME) {});
YUI.add('mojito-composite-addon', function(Y, NAME) {});
YUI.add('mojito-config-addon', function(Y, NAME) {});
YUI.add('mojito-cookie-addon', function(Y, NAME) {});
YUI.add('mojito-deploy-addon', function(Y, NAME) {});
YUI.add('mojito-device-addon', function(Y, NAME) {});
YUI.add('mojito-http-addon', function(Y, NAME) {});
YUI.add('mojito-models-addon', function(Y, NAME) {});
YUI.add('mojito-i13n-addon', function(Y, NAME) {});
YUI.add('mojito-intl-addon', function(Y, NAME) {});
YUI.add('mojito-meta-addon', function(Y, NAME) {});
YUI.add('mojito-params-addon', function(Y, NAME) {});
YUI.add('mojito-partial-addon', function(Y, NAME) {});
YUI.add('mojito-url-addon', function(Y, NAME) {});

/* RS ADDONS */
YUI.add('addon-rs-config', function(Y, NAME) {});
YUI.add('addon-rs-dispatch-helper', function(Y, NAME) {});
YUI.add('addon-rs-selector', function(Y, NAME) {});
YUI.add('addon-rs-url', function(Y, NAME) {});
YUI.add('addon-rs-yui', function(Y, NAME) {});

/* VIEW ENGINE ADDONS */
YUI.add('mojito-hb', function(Y, NAME) {});
YUI.add('mojito-mu', function(Y, NAME) {});

/* AUTOLOAD */
YUI.add('mojito-action-context', function(Y, NAME) {});
YUI.add('mojito-dispatcher', function(Y, NAME) {});
YUI.add('mojito-mojit-proxy', function(Y, NAME) {});
YUI.add('mojito-output-handler', function(Y, NAME) {});
YUI.add('mojito-perf', function(Y, NAME) {});
YUI.add('mojito-resource-store', function(Y, NAME) {});
YUI.add('mojito-rest-lib', function(Y, NAME) {});
YUI.add('mojito-route-maker', function(Y, NAME) {});
YUI.add('mojito-client-store', function(Y, NAME) {});
YUI.add('mojito-tunnel-client', function(Y, NAME) {});
YUI.add('mojito-util', function(Y, NAME) {});
YUI.add('mojito-view-renderer', function(Y, NAME) {});

YUI.add('mojito-test', function(Y, NAME) {

    function EasyMock() {

        var mock = Y.Test.Mock();

        mock.expect = function() {
            Y.Array.each(arguments, function(expectation) {
                Y.Test.Mock.expect(mock, expectation);
            });
            return mock;
        };

        mock.verify = function() {
            Y.Test.Mock.verify(mock);
        };

        return mock;
    }

    function createMockAddon(source, name) {
        source._addons.push(name);
        source[name] = new EasyMock();
    }

    function createMockModel(source, name) {
        source.models[name] = new EasyMock();
    }

    function createMockExtra(source, ns, name) {
        var mock = new EasyMock();

        if (!source[ns]) {
            source[ns] = {};
        }
        if (!source._extras[ns]) {
            source._extras[ns] = {};
        }
        source._extras[ns][name] = mock;
        source[ns][name] = mock;
    }

    function MockActionContext(opts) {
        var mock = Y.Test.Mock();

        opts = opts || {};
        mock._addons = [];
        mock.models = {};
        mock._extras = {};

        if (opts.addons) {
            Y.Array.each(opts.addons, function(addon) {
                createMockAddon(mock, addon);
            });
        }
        if (opts.models) {
            Y.Array.each(opts.models, function(model) {
                createMockModel(mock, model);
            });
        }
        if (opts.extras) {
            Y.Object.each(opts.extras, function(extras, namespace) {
                if (Y.Lang.isArray(extras)) {
                    Y.Array.each(extras, function(extra) {
                        createMockExtra(mock, namespace, extra);
                    });
                } else {
                    createMockExtra(mock, namespace, extras);
                }
            });
        }

        mock.expect = function() {
            Y.Array.each(arguments, function(expectation) {
                Y.Test.Mock.expect(mock, expectation);
            });
            return mock;
        };
        mock.verify = function() {
            var i,
                j,
                mockAddon;

            Y.Test.Mock.verify(mock);
            for (i = 0; i < mock._addons.length; i += 1) {
                mockAddon = mock[mock._addons[i]];
                mockAddon.verify();
            }
            for (i in mock.models) {
                if (mock.models.hasOwnProperty(i)) {
                    mock.models[i].verify();
                }
            }
            for (i in mock._extras) {
                if (mock._extras.hasOwnProperty(i)) {
                    for (j in mock._extras[i]) {
                        if (mock._extras[i].hasOwnProperty(j)) {
                            mock._extras[i][j].verify();
                        }
                    }
                }
            }
        };
        return mock;
    }

    Y.mojito.MockActionContext = MockActionContext;
    Y.mojito.EasyMock = EasyMock;

}, '0.1.0', {requires: [
    'event',
    "node",
    "node-event-simulate"
]});

YUI.add('mojito-test-extra', function(Y, NAME) {
    var A = Y.Assert;

	Y.MOJITO_DIR = ('undefined' !== typeof require) ?
	    require('path').resolve(__dirname, '../../') + '/' : null;

    // path doesn't need to be given, mainly used during recursion
    Y.TEST_CMP = function (x, y, msg, path) {
        path = path || 'obj';
        var i;
        if (Y.Lang.isArray(x)) {
            A.isArray(x, path + ': ' + (msg || 'first arg should be an array'));
            A.isArray(y, path + ': ' + (msg || 'second arg should be an array'));
            A.areSame(x.length, y.length, path + ': ' + (msg || 'arrays are different lengths'));
            for (i = 0; i < x.length; i += 1) {
                Y.TEST_CMP(x[i], y[i], msg, path + '[' + i + ']');
            }
            return;
        }
        if (Y.Lang.isObject(x)) {
            A.isObject(x, path + ': ' + (msg || 'first arg should be an object'));
            A.isObject(y, path + ': ' + (msg || 'second arg should be an object'));
            A.areSame(Y.Object.keys(x).length, Y.Object.keys(y).length, path + ': ' + (msg || 'object keys are different lengths'));
            for (i in x) {
                if (x.hasOwnProperty(i)) {
                    Y.TEST_CMP(x[i], y[i], msg, path + '{' + i + '}');
                }
            }
            return;
        }
        A.areSame(x, y, path + ': ' + (msg || 'args should be the same'));
    };

}, '0.1.0', {requires: ['test']});
<commit_msg>added enableHookGroup to test stubs<commit_after>/*
 * Copyright (c) 2011-2013, Yahoo! Inc.  All rights reserved.
 * Copyrights licensed under the New BSD License.
 * See the accompanying LICENSE file for terms.
 */

/*jslint anon:true, sloppy:true, nomen:true, node:true*/
/*global YUI*/

/*
 * Baseline Mojito client testing harness.
 */
YUI.add('mojito', function(Y, NAME) {

    // TODO: why does need to be in sync with autoload/mojito.common.js
    // why don't we just attach that to every test?

    Y.namespace('mojito');
    Y.namespace('mojito.trans');
    Y.namespace('mojito.actions');
    Y.namespace('mojito.binders');
    Y.namespace('mojito.controllers');
    Y.namespace('mojito.models');
    Y.namespace('mojito.addons');
    Y.namespace('mojito.addons.ac');
    Y.namespace('mojito.addons.viewEngines');
    // HookSystem::StartBlock
    Y.mojito.hooks = {
        hook: function () {},
        registerHook: function () {},
        enableHookGroup: function () {}
    };
    // HookSystem::EndBlock

    // this is a facade for the real implementation from mojito-perf module
    // that will have to be plugged manually to get the metrics in the
    // console or a log file.
    Y.mojito.perf = {
        timeline: function () {
            return {
                done: function () {}
            };
        },
        mark: function () {}
    };

    // internal mojito framework cache (this is probably legacy)
    YUI.namespace('_mojito._cache');

    // setting the stage for all data-scopes implementation
    YUI.namespace('Env.mojito');

});

/* AC ADDONS */
YUI.add('mojito-analytics-addon', function(Y, NAME) {});
YUI.add('mojito-assets-addon', function(Y, NAME) {});
YUI.add('mojito-carrier-addon', function(Y, NAME) {});
YUI.add('mojito-composite-addon', function(Y, NAME) {});
YUI.add('mojito-config-addon', function(Y, NAME) {});
YUI.add('mojito-cookie-addon', function(Y, NAME) {});
YUI.add('mojito-deploy-addon', function(Y, NAME) {});
YUI.add('mojito-device-addon', function(Y, NAME) {});
YUI.add('mojito-http-addon', function(Y, NAME) {});
YUI.add('mojito-models-addon', function(Y, NAME) {});
YUI.add('mojito-i13n-addon', function(Y, NAME) {});
YUI.add('mojito-intl-addon', function(Y, NAME) {});
YUI.add('mojito-meta-addon', function(Y, NAME) {});
YUI.add('mojito-params-addon', function(Y, NAME) {});
YUI.add('mojito-partial-addon', function(Y, NAME) {});
YUI.add('mojito-url-addon', function(Y, NAME) {});

/* RS ADDONS */
YUI.add('addon-rs-config', function(Y, NAME) {});
YUI.add('addon-rs-dispatch-helper', function(Y, NAME) {});
YUI.add('addon-rs-selector', function(Y, NAME) {});
YUI.add('addon-rs-url', function(Y, NAME) {});
YUI.add('addon-rs-yui', function(Y, NAME) {});

/* VIEW ENGINE ADDONS */
YUI.add('mojito-hb', function(Y, NAME) {});
YUI.add('mojito-mu', function(Y, NAME) {});

/* AUTOLOAD */
YUI.add('mojito-action-context', function(Y, NAME) {});
YUI.add('mojito-dispatcher', function(Y, NAME) {});
YUI.add('mojito-mojit-proxy', function(Y, NAME) {});
YUI.add('mojito-output-handler', function(Y, NAME) {});
YUI.add('mojito-perf', function(Y, NAME) {});
YUI.add('mojito-resource-store', function(Y, NAME) {});
YUI.add('mojito-rest-lib', function(Y, NAME) {});
YUI.add('mojito-route-maker', function(Y, NAME) {});
YUI.add('mojito-client-store', function(Y, NAME) {});
YUI.add('mojito-tunnel-client', function(Y, NAME) {});
YUI.add('mojito-util', function(Y, NAME) {});
YUI.add('mojito-view-renderer', function(Y, NAME) {});

YUI.add('mojito-test', function(Y, NAME) {

    function EasyMock() {

        var mock = Y.Test.Mock();

        mock.expect = function() {
            Y.Array.each(arguments, function(expectation) {
                Y.Test.Mock.expect(mock, expectation);
            });
            return mock;
        };

        mock.verify = function() {
            Y.Test.Mock.verify(mock);
        };

        return mock;
    }

    function createMockAddon(source, name) {
        source._addons.push(name);
        source[name] = new EasyMock();
    }

    function createMockModel(source, name) {
        source.models[name] = new EasyMock();
    }

    function createMockExtra(source, ns, name) {
        var mock = new EasyMock();

        if (!source[ns]) {
            source[ns] = {};
        }
        if (!source._extras[ns]) {
            source._extras[ns] = {};
        }
        source._extras[ns][name] = mock;
        source[ns][name] = mock;
    }

    function MockActionContext(opts) {
        var mock = Y.Test.Mock();

        opts = opts || {};
        mock._addons = [];
        mock.models = {};
        mock._extras = {};

        if (opts.addons) {
            Y.Array.each(opts.addons, function(addon) {
                createMockAddon(mock, addon);
            });
        }
        if (opts.models) {
            Y.Array.each(opts.models, function(model) {
                createMockModel(mock, model);
            });
        }
        if (opts.extras) {
            Y.Object.each(opts.extras, function(extras, namespace) {
                if (Y.Lang.isArray(extras)) {
                    Y.Array.each(extras, function(extra) {
                        createMockExtra(mock, namespace, extra);
                    });
                } else {
                    createMockExtra(mock, namespace, extras);
                }
            });
        }

        mock.expect = function() {
            Y.Array.each(arguments, function(expectation) {
                Y.Test.Mock.expect(mock, expectation);
            });
            return mock;
        };
        mock.verify = function() {
            var i,
                j,
                mockAddon;

            Y.Test.Mock.verify(mock);
            for (i = 0; i < mock._addons.length; i += 1) {
                mockAddon = mock[mock._addons[i]];
                mockAddon.verify();
            }
            for (i in mock.models) {
                if (mock.models.hasOwnProperty(i)) {
                    mock.models[i].verify();
                }
            }
            for (i in mock._extras) {
                if (mock._extras.hasOwnProperty(i)) {
                    for (j in mock._extras[i]) {
                        if (mock._extras[i].hasOwnProperty(j)) {
                            mock._extras[i][j].verify();
                        }
                    }
                }
            }
        };
        return mock;
    }

    Y.mojito.MockActionContext = MockActionContext;
    Y.mojito.EasyMock = EasyMock;

}, '0.1.0', {requires: [
    'event',
    "node",
    "node-event-simulate"
]});

YUI.add('mojito-test-extra', function(Y, NAME) {
    var A = Y.Assert;

	Y.MOJITO_DIR = ('undefined' !== typeof require) ?
	    require('path').resolve(__dirname, '../../') + '/' : null;

    // path doesn't need to be given, mainly used during recursion
    Y.TEST_CMP = function (x, y, msg, path) {
        path = path || 'obj';
        var i;
        if (Y.Lang.isArray(x)) {
            A.isArray(x, path + ': ' + (msg || 'first arg should be an array'));
            A.isArray(y, path + ': ' + (msg || 'second arg should be an array'));
            A.areSame(x.length, y.length, path + ': ' + (msg || 'arrays are different lengths'));
            for (i = 0; i < x.length; i += 1) {
                Y.TEST_CMP(x[i], y[i], msg, path + '[' + i + ']');
            }
            return;
        }
        if (Y.Lang.isObject(x)) {
            A.isObject(x, path + ': ' + (msg || 'first arg should be an object'));
            A.isObject(y, path + ': ' + (msg || 'second arg should be an object'));
            A.areSame(Y.Object.keys(x).length, Y.Object.keys(y).length, path + ': ' + (msg || 'object keys are different lengths'));
            for (i in x) {
                if (x.hasOwnProperty(i)) {
                    Y.TEST_CMP(x[i], y[i], msg, path + '{' + i + '}');
                }
            }
            return;
        }
        A.areSame(x, y, path + ': ' + (msg || 'args should be the same'));
    };

}, '0.1.0', {requires: ['test']});
<|endoftext|>


<commit_before>var expandable1 = $("#expandable-1").expandable(),
    showEvent = jasmine.createSpy('showEvent'),
    hideEvent = jasmine.createSpy('hideEvent'),
    readyEvent = jasmine.createSpy('readyEvent'),
    expandable2 = $("#expandable-2").expandable({
        'container': $('#container-2')
    }),
    expandable3 = $("#expandable-3").expandable({
        'shown': true,
        'toggle': false
    });

describe('Expandable', function () {
    expandable1
        .on('ready', function () { readyEvent(); })
        .on('show', function () { showEvent(); })
        .on('hide', function () { hideEvent(); });

    it('should be defined on ch object', function () {
        expect(ch.hasOwnProperty('Expandable')).toBeTruthy();
        expect(typeof ch.Expandable).toEqual('function');
    });

    it('should be defined on $ object', function () {
        expect($.fn.hasOwnProperty('expandable')).toBeTruthy();
        expect(typeof $.fn.expandable).toEqual('function');
    });

    it('should be return a new instance', function () {
        expect(expandable1 instanceof ch.Expandable).toBeTruthy();
    });

    it('should emit the "ready" event when it\'s created', function () {
        waits(50);
        runs(function () {
            expect(readyEvent).toHaveBeenCalled();
        });
    });
});

describe('It should have the following public properties:', function () {

    it('.el', function () {
        expect(expandable1.el).not.toEqual(undefined);
        expect(expandable1.el.nodeType).toEqual(1);
    });

    it('.$el', function () {
        expect(expandable1.$el).not.toEqual(undefined);
        expect(expandable1.$el instanceof $).toBeTruthy();
    });

    it('.name', function () {
        expect(expandable1.name).not.toEqual(undefined);
        expect(typeof expandable1.name).toEqual('string');
        expect(expandable1.name).toEqual('expandable');
    });

    it('.constructor', function () {
        expect(expandable1.constructor).not.toEqual(undefined);
        expect(typeof expandable1.constructor).toEqual('function');
    });

    it('.uid', function () {
        expect(expandable1.uid).not.toEqual(undefined);
        expect(typeof expandable1.uid).toEqual('number');
    });

});

describe('It should have the following public methods:', function () {
    var methods = ['init', 'destroy', 'show', 'hide', 'isShown', 'enable', 'disable'],
        i = 0,
        len = methods.length;

    for (i; i < len; i += 1) {
        (function (i){
            it('.' + methods[i] + '()', function () {
                expect(expandable1[methods[i]]).not.toEqual(undefined);
                expect(typeof expandable1[methods[i]]).toEqual('function');
            });
        }(i));
    }
});

describe('It should use the following abilities:', function () {
    it('EventEmitter', function () {
        expect(expandable1.on).not.toEqual(undefined);
        expect(typeof expandable1.on).toEqual('function');
    });

    it('Content', function () {
        expect(expandable1.content).not.toEqual(undefined);
        expect(typeof expandable1.content).toEqual('function');
    });

    it('Collapsible', function () {
        expect(expandable1._show).not.toEqual(undefined);
        expect(typeof expandable1._show).toEqual('function');
    });
});

describe('It should have a trigger and', function () {
    var $trigger = expandable1.$trigger;

    it('should exist', function () {
        expect($trigger).not.toEqual(undefined);
        expect($trigger[0].nodeType).toEqual(1);
        expect($trigger instanceof $).toBeTruthy();
    });

    it('should have the WAI-ARIA attribute "aria-controls"', function () {
       expect($trigger.attr('aria-controls')).toEqual(expandable1.$container[0].id);
    });

    describe('should have the following class names:', function () {

        it('.ch-expandable-trigger', function () {
            expect($trigger.hasClass('ch-expandable-trigger')).toBeTruthy();
        });

        it('.ch-expandable-ico', function () {
            expect($trigger.hasClass('ch-expandable-ico')).toBeTruthy();
        });

        it('.ch-user-no-select', function () {
            expect($trigger.hasClass('ch-user-no-select')).toBeTruthy();
        });
    });

});

describe('It should have a container and', function () {
    var $container = expandable1.$container;

    it('should exist', function () {
        expect($container).not.toEqual(undefined);
        expect($container[0].nodeType).toEqual(1);
        expect($container instanceof $).toBeTruthy();
    });

    it('shold be hidden', function () {
        expect($container.hasClass('ch-hide')).toBeTruthy();
    });

    it('should have the WAI-ARIA attribute "aria-expanded" in "false"', function () {
       expect($container.attr('aria-expanded')).toEqual('false');
    });

    describe('Should have the following class names:', function () {

        it('.ch-expandable-container', function () {
            expect($container.hasClass('ch-expandable-container')).toBeTruthy();
        });

    });
});

describe('Its show() method', function () {
    var $trigger = expandable1.$trigger,
        $container = expandable1.$container,
        show;

    it('should add "ch-expandable-trigger-on" class name to trigger', function () {
        expect($trigger.hasClass('ch-expandable-trigger-on')).toBeFalsy();
        show = expandable1.show();
        expect($trigger.hasClass('ch-expandable-trigger-on')).toBeTruthy();
    });

    it('should remove "ch-hide" class name from container.', function () {
        expect($container.hasClass('ch-hide')).toBeFalsy();
    });

    it('should update the WAI-ARIA attribute "aria-expanded" to "true" on container', function () {
        expect($container.attr('aria-expanded')).toEqual('true');
    });

    it('should emit the "show" event', function () {
        expect(showEvent).toHaveBeenCalled();
    });

    describe('Public instance', function () {
        it('should return the same instance than initialized widget', function () {
            expect(show).toEqual(expandable1);
        });
    });
});

describe('Its hide() method', function () {
    var $trigger = expandable1.$trigger,
        $container = expandable1.$container,
        hide;

    it('should remove "ch-expandable-trigger-on" class name to trigger', function () {
        hide = expandable1.hide();
        expect($trigger.hasClass('ch-expandable-trigger-on')).toBeFalsy();
    });

    it('should add "ch-hide" class name to container', function () {
        expect($container.hasClass('ch-hide')).toBeTruthy();
    });

    it('should update the WAI-ARIA attribute "aria-expanded" to "false" on container', function () {
        expect($container.attr('aria-expanded')).toEqual('false');
    });

    it('should emit the "hide" event', function () {
        expect(showEvent).toHaveBeenCalled();
    });

    describe('Public instance', function () {
        it('should return the same instance than initialized widget', function () {
            expect(hide).toEqual(expandable1);
        });
    });
});

describe('Its isShown() method', function () {
    var isShown;

    it('should return "true" when the widget is shown', function () {
        expandable1.show();
        isShown = expandable1.isShown();

        expect(typeof isShown).toEqual('boolean');
        expect(isShown).toBeTruthy();
    });

    it('should return "false" when the widget is hidden', function () {
        expandable1.hide();
        isShown = expandable1.isShown();

        expect(typeof isShown).toEqual('boolean');
        expect(isShown).toBeFalsy();
    });

    expandable1.hide();
});

describe('Its disable() method', function () {
    it('should prevent to show its container', function () {
        expandable1.disable();
        expandable1.show();
        expect(expandable1.$trigger.hasClass('ch-expandable-trigger-on')).toBeFalsy();
    });
});

describe('Its enable() method', function () {
    it('should prevent to show its container', function () {
        expandable1.enable();
        expandable1.show();
        expect(expandable1.$trigger.hasClass('ch-expandable-trigger-on')).toBeTruthy();
    });
    expandable1.hide();
});

describe('Instance an Expandable configured', function () {

    it('with custom container', function () {
        var $container = expandable2.$container;
        expect($container).not.toEqual(undefined);
        expect($container[0].nodeType).toEqual(1);
        expect($container instanceof $).toBeTruthy();
        expect($container).toEqual($('#container-2'));
    });

    it('shown by default', function () {
        expect(expandable3.$trigger.hasClass('ch-expandable-trigger-on')).toBeTruthy();
    });

    it('without toggle', function () {
        expandable3.show();
        expect(expandable3.$trigger.hasClass('ch-expandable-trigger-on')).toBeTruthy();

        expandable3.hide();
        expect(expandable3.$trigger.hasClass('ch-expandable-trigger-on')).toBeFalsy();
    });
});<commit_msg>#987 Expandable: Move abilities tests.<commit_after>var expandable1 = $("#expandable-1").expandable(),
    showEvent = jasmine.createSpy('showEvent'),
    hideEvent = jasmine.createSpy('hideEvent'),
    readyEvent = jasmine.createSpy('readyEvent'),
    expandable2 = $("#expandable-2").expandable({
        'container': $('#container-2')
    }),
    expandable3 = $("#expandable-3").expandable({
        'shown': true,
        'toggle': false
    });

describe('Expandable', function () {
    expandable1
        .on('ready', function () { readyEvent(); })
        .on('show', function () { showEvent(); })
        .on('hide', function () { hideEvent(); });

    it('should be defined on ch object', function () {
        expect(ch.hasOwnProperty('Expandable')).toBeTruthy();
        expect(typeof ch.Expandable).toEqual('function');
    });

    it('should be defined on $ object', function () {
        expect($.fn.hasOwnProperty('expandable')).toBeTruthy();
        expect(typeof $.fn.expandable).toEqual('function');
    });

    it('should be return a new instance', function () {
        expect(expandable1 instanceof ch.Expandable).toBeTruthy();
    });

    it('should emit the "ready" event when it\'s created', function () {
        waits(50);
        runs(function () {
            expect(readyEvent).toHaveBeenCalled();
        });
    });

    describe('should use the following abilities:', function () {
        it('EventEmitter', function () {
            expect(expandable1.on).not.toEqual(undefined);
            expect(typeof expandable1.on).toEqual('function');
        });

        it('Content', function () {
            expect(expandable1.content).not.toEqual(undefined);
            expect(typeof expandable1.content).toEqual('function');
        });

        it('Collapsible', function () {
            expect(expandable1._show).not.toEqual(undefined);
            expect(typeof expandable1._show).toEqual('function');
        });
    });
});

describe('It should have the following public properties:', function () {

    it('.el', function () {
        expect(expandable1.el).not.toEqual(undefined);
        expect(expandable1.el.nodeType).toEqual(1);
    });

    it('.$el', function () {
        expect(expandable1.$el).not.toEqual(undefined);
        expect(expandable1.$el instanceof $).toBeTruthy();
    });

    it('.name', function () {
        expect(expandable1.name).not.toEqual(undefined);
        expect(typeof expandable1.name).toEqual('string');
        expect(expandable1.name).toEqual('expandable');
    });

    it('.constructor', function () {
        expect(expandable1.constructor).not.toEqual(undefined);
        expect(typeof expandable1.constructor).toEqual('function');
    });

    it('.uid', function () {
        expect(expandable1.uid).not.toEqual(undefined);
        expect(typeof expandable1.uid).toEqual('number');
    });

});

describe('It should have the following public methods:', function () {
    var methods = ['init', 'destroy', 'show', 'hide', 'isShown', 'enable', 'disable'],
        i = 0,
        len = methods.length;

    for (i; i < len; i += 1) {
        (function (i){
            it('.' + methods[i] + '()', function () {
                expect(expandable1[methods[i]]).not.toEqual(undefined);
                expect(typeof expandable1[methods[i]]).toEqual('function');
            });
        }(i));
    }
});

describe('It should have a trigger and', function () {
    var $trigger = expandable1.$trigger;

    it('should exist', function () {
        expect($trigger).not.toEqual(undefined);
        expect($trigger[0].nodeType).toEqual(1);
        expect($trigger instanceof $).toBeTruthy();
    });

    it('should have the WAI-ARIA attribute "aria-controls"', function () {
       expect($trigger.attr('aria-controls')).toEqual(expandable1.$container[0].id);
    });

    describe('should have the following class names:', function () {

        it('.ch-expandable-trigger', function () {
            expect($trigger.hasClass('ch-expandable-trigger')).toBeTruthy();
        });

        it('.ch-expandable-ico', function () {
            expect($trigger.hasClass('ch-expandable-ico')).toBeTruthy();
        });

        it('.ch-user-no-select', function () {
            expect($trigger.hasClass('ch-user-no-select')).toBeTruthy();
        });
    });

});

describe('It should have a container and', function () {
    var $container = expandable1.$container;

    it('should exist', function () {
        expect($container).not.toEqual(undefined);
        expect($container[0].nodeType).toEqual(1);
        expect($container instanceof $).toBeTruthy();
    });

    it('shold be hidden', function () {
        expect($container.hasClass('ch-hide')).toBeTruthy();
    });

    it('should have the WAI-ARIA attribute "aria-expanded" in "false"', function () {
       expect($container.attr('aria-expanded')).toEqual('false');
    });

    describe('Should have the following class names:', function () {

        it('.ch-expandable-container', function () {
            expect($container.hasClass('ch-expandable-container')).toBeTruthy();
        });

    });
});

describe('Its show() method', function () {
    var $trigger = expandable1.$trigger,
        $container = expandable1.$container,
        show;

    it('should add "ch-expandable-trigger-on" class name to trigger', function () {
        expect($trigger.hasClass('ch-expandable-trigger-on')).toBeFalsy();
        show = expandable1.show();
        expect($trigger.hasClass('ch-expandable-trigger-on')).toBeTruthy();
    });

    it('should remove "ch-hide" class name from container.', function () {
        expect($container.hasClass('ch-hide')).toBeFalsy();
    });

    it('should update the WAI-ARIA attribute "aria-expanded" to "true" on container', function () {
        expect($container.attr('aria-expanded')).toEqual('true');
    });

    it('should emit the "show" event', function () {
        expect(showEvent).toHaveBeenCalled();
    });

    describe('Public instance', function () {
        it('should return the same instance than initialized widget', function () {
            expect(show).toEqual(expandable1);
        });
    });
});

describe('Its hide() method', function () {
    var $trigger = expandable1.$trigger,
        $container = expandable1.$container,
        hide;

    it('should remove "ch-expandable-trigger-on" class name to trigger', function () {
        hide = expandable1.hide();
        expect($trigger.hasClass('ch-expandable-trigger-on')).toBeFalsy();
    });

    it('should add "ch-hide" class name to container', function () {
        expect($container.hasClass('ch-hide')).toBeTruthy();
    });

    it('should update the WAI-ARIA attribute "aria-expanded" to "false" on container', function () {
        expect($container.attr('aria-expanded')).toEqual('false');
    });

    it('should emit the "hide" event', function () {
        expect(showEvent).toHaveBeenCalled();
    });

    describe('Public instance', function () {
        it('should return the same instance than initialized widget', function () {
            expect(hide).toEqual(expandable1);
        });
    });
});

describe('Its isShown() method', function () {
    var isShown;

    it('should return "true" when the widget is shown', function () {
        expandable1.show();
        isShown = expandable1.isShown();

        expect(typeof isShown).toEqual('boolean');
        expect(isShown).toBeTruthy();
    });

    it('should return "false" when the widget is hidden', function () {
        expandable1.hide();
        isShown = expandable1.isShown();

        expect(typeof isShown).toEqual('boolean');
        expect(isShown).toBeFalsy();
    });

    expandable1.hide();
});

describe('Its disable() method', function () {
    it('should prevent to show its container', function () {
        expandable1.disable();
        expandable1.show();
        expect(expandable1.$trigger.hasClass('ch-expandable-trigger-on')).toBeFalsy();
    });
});

describe('Its enable() method', function () {
    it('should prevent to show its container', function () {
        expandable1.enable();
        expandable1.show();
        expect(expandable1.$trigger.hasClass('ch-expandable-trigger-on')).toBeTruthy();
    });
    expandable1.hide();
});

describe('Instance an Expandable configured', function () {

    it('with custom container', function () {
        var $container = expandable2.$container;
        expect($container).not.toEqual(undefined);
        expect($container[0].nodeType).toEqual(1);
        expect($container instanceof $).toBeTruthy();
        expect($container).toEqual($('#container-2'));
    });

    it('shown by default', function () {
        expect(expandable3.$trigger.hasClass('ch-expandable-trigger-on')).toBeTruthy();
    });

    it('without toggle', function () {
        expandable3.show();
        expect(expandable3.$trigger.hasClass('ch-expandable-trigger-on')).toBeTruthy();

        expandable3.hide();
        expect(expandable3.$trigger.hasClass('ch-expandable-trigger-on')).toBeFalsy();
    });
});<|endoftext|>


<commit_before>Brooklyn.dashboard = (function(parent){
    function loadWidgets(){
        $( ".column" ).sortable({
			connectWith: ".column"
		});
        $( ".master-column-wrapper" ).sortable({
			connectWith: ".master-column-wrapper"
		});
		$( ".portlet" ).addClass( "ui-widget ui-widget-content ui-helper-clearfix ui-corner-all" )
			.find( ".portlet-header" )
				.addClass( "ui-widget-header ui-corner-all" )
				.prepend( "")
				.end()
			.find( ".portlet-content" );
		$( ".portlet-header .ui-icon" ).click(function() {
			$( this ).toggleClass( "ui-icon-minusthick" ).toggleClass( "ui-icon-plusthick" );
			$( this ).parents( ".portlet:first" ).find( ".portlet-content" ).toggle();
		});
		$( ".column" ).disableSelection();
    }
    function init(){
        loadWidgets();
    }

    return{
        init: init
    };
})();
$(document).ready(Brooklyn.dashboard.init);
<commit_msg>Dashboard Widgets now only draggable by header.<commit_after>Brooklyn.dashboard = (function(parent){
    function loadWidgets(){
        $( ".column" ).sortable({
			connectWith: ".column",
            handle: ".portlet-header",
            cursor: "crosshair"
		});
        $( ".master-column-wrapper" ).sortable({
			connectWith: ".master-column-wrapper",
            handle: ".portlet-header",
            cursor: "crosshair"
		});
		$( ".portlet" ).addClass( "ui-widget ui-widget-content ui-helper-clearfix ui-corner-all" )
			.find( ".portlet-header" )
				.addClass( "ui-widget-header ui-corner-all" )
				.prepend( "")
				.end()
			.find( ".portlet-content" );
		$( ".portlet-header .ui-icon" ).click(function() {
			$( this ).toggleClass( "ui-icon-minusthick" ).toggleClass( "ui-icon-plusthick" );
			$( this ).parents( ".portlet:first" ).find( ".portlet-content" ).toggle();
		});
		$( ".column" ).disableSelection();
    }
    function init(){
        loadWidgets();
    }

    return{
        init: init
    };
})();
$(document).ready(Brooklyn.dashboard.init);
<|endoftext|>


<commit_before>var AnalysisOptionModel = require('./analysis-option-model');

/**
 * Custom model for kmeans type
 */
module.exports = AnalysisOptionModel.extend({

});
<commit_msg>Removes unused file<commit_after><|endoftext|>


<commit_before>'use strict';

const commonConfig = require('./webpack.common');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const merge = require('webpack-merge');
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
const webpack = require('webpack');

// const BrotliPlugin = require('brotli-webpack-plugin');
const ZopfliPlugin = require('zopfli-webpack-plugin');

module.exports = merge(commonConfig, {
    plugins: [
        new CleanWebpackPlugin(['build']),
        new webpack.DefinePlugin({
            'process.env': {
                'NODE_ENV': '"production"'
            }
        }),
        new HtmlWebpackPlugin({
            template: './src/index.ejs',
            inject: false,
            minify: {
                collapseBooleanAttributes: true,
                collapseInlineTagWhitespace: true,
                collapseWhitespace: true,
                minifyCSS: true,
                minifyJS: true,
                removeAttributeQuotes: true,
                removeComments: true,
                removeOptionalTags: true,
                removeRedundantAttributes: true,
                removeScriptTypeAttributes: true,
                removeStyleLinkTypeAttributes: true,
                sortAttributes: true,
                sortClassName: true,
                useShortDoctype: true,
                removeTagWhitespace: true,
                trimCustomFragments: true
            },
            hash: true
        }),
        new UglifyJSPlugin(),
        new ZopfliPlugin(),
        // new BrotliPlugin()
    ]
});
<commit_msg>Enable brotli<commit_after>'use strict';

const commonConfig = require('./webpack.common');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const merge = require('webpack-merge');
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
const webpack = require('webpack');

const BrotliPlugin = require('brotli-webpack-plugin');
const ZopfliPlugin = require('zopfli-webpack-plugin');

module.exports = merge(commonConfig, {
    plugins: [
        new CleanWebpackPlugin(['build']),
        new webpack.DefinePlugin({
            'process.env': {
                'NODE_ENV': '"production"'
            }
        }),
        new HtmlWebpackPlugin({
            template: './src/index.ejs',
            inject: false,
            minify: {
                collapseBooleanAttributes: true,
                collapseInlineTagWhitespace: true,
                collapseWhitespace: true,
                minifyCSS: true,
                minifyJS: true,
                removeAttributeQuotes: true,
                removeComments: true,
                removeOptionalTags: true,
                removeRedundantAttributes: true,
                removeScriptTypeAttributes: true,
                removeStyleLinkTypeAttributes: true,
                sortAttributes: true,
                sortClassName: true,
                useShortDoctype: true,
                removeTagWhitespace: true,
                trimCustomFragments: true
            },
            hash: true
        }),
        new UglifyJSPlugin(),
        new ZopfliPlugin({
            threshold: 10240
        }),
        new BrotliPlugin({
            threshold: 10240
        })
    ]
});
<|endoftext|>


<commit_before>/*
The MIT License (MIT)
Copyright (c) 2014 NTHUOJ team
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/*
the target element
start time should put in tag with given id

2015/3/16 12:00:23

Usage: timer("timer");
*/
function timer(id) {
    var server_time = new Date(document.getElementById(id).innerHTML);
    var now = new Date();
    var offset = server_time.getTime() - now.getTime();
    var t = setTimeout(function() {
        showTime(id,offset);
    }, 1000);
}

function checkTime(i) {
    if (i < 10) {
        i = "0" + i
    }; // add zero in front of numbers < 10
    return i;
}

function showTime(id,offset) {
    time = new Date();
    time = time.getTime() + offset;
    time = new Date(time);

    y = time.getFullYear();

    m = time.getMonth()+1;

    d = time.getDate();

    h = time.getHours();
    h = checkTime(h);

    min = time.getMinutes();
    min = checkTime(min);

    s = time.getSeconds();
    s = checkTime(s);

    document.getElementById(id).innerHTML = y + "/" + m + "/" + d + " " + h + ":" + min + ":" + s;
    var t = setTimeout(function() {
        showTime(id,offset);
    }, 1000);
}
<commit_msg>use js clock<commit_after>/*
The MIT License (MIT)
Copyright (c) 2014 NTHUOJ team
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/*
the target element
start time should put in tag with given id

2015/3/16 12:00:23

Usage: timer("timer");
*/
$(function(){
    timer("time");
});
function timer(id) {
    var server_time = new Date(document.getElementById('time').innerHTML);
    var now = new Date();
    var offset = server_time.getTime() - now.getTime();
    var t = setTimeout(function() {
        showTime(id,offset);
    }, 1000);
}

function checkTime(i) {
    if (i < 10) {
        i = "0" + i
    }; // add zero in front of numbers < 10
    return i;
}

function showTime(id,offset) {
    time = new Date();
    time = time.getTime() + offset;
    time = new Date(time);

    y = time.getFullYear();

    m = time.getMonth()+1;

    d = time.getDate();

    h = time.getHours();
    h = checkTime(h);

    min = time.getMinutes();
    min = checkTime(min);

    s = time.getSeconds();
    s = checkTime(s);

    document.getElementById(id).innerHTML = y + "/" + m + "/" + d + " " + h + ":" + min + ":" + s;
    var t = setTimeout(function() {
        showTime(id,offset);
    }, 1000);
}
<|endoftext|>


<commit_before>const Discord = require("discord.js")
, express = require("express")
, passport = require("passport")
, Strategy = require("passport-discord").Strategy
, session = require("express-session")
, fs = require("fs-extra")
, join = require("path").join;

var router = express.Router()
, locals = {};

// ===== [ DISCORD AUTH ] ===== //

passport.serializeUser(function(user, done) {
    done(null, user);
});
passport.deserializeUser(function(obj, done) {
    done(null, obj);
});

passport.use(new Strategy({
    clientID: client.config.oauth.id,
    clientSecret: client.config.oauth.secret,
    callbackURL: client.config.oauth.callback,
    scope: ["identify", "guilds"]
}, function(accessToken, refreshToken, profile, done) {
    process.nextTick(function() {
        return done(null, profile);
    });
}));
router.use(session({
    secret: utils.genSecret(),
    resave: false,
    saveUninitialized: false
}));
router.use(passport.initialize());
router.use(passport.session());

router.get("/login", isLoggedIn, function(req, res)
{
    res.redirect("/dashboard");
});

router.get("/actuallylogin", passport.authenticate("discord", { scope: ["identify", "guilds"] }), (req, res) => {});

router.get("/callback", passport.authenticate("discord", { failureRedirect: "/" }), function(req, res)
{
    const userDir = join(__data, "users", req.user.id);

    fs.readdir(join(__data, "users"), (err, users) => {
        if (err) console.error(err);

        fs.outputJson(`${userDir}/user.json`, req.user, (err) => {
            if (err) console.error(err);

            res.redirect("/dashboard");
        });
    });
});

router.get("/logout", function(req, res) {
    req.logout();
    res.redirect("/");
});

// ===== [ HELPER FUNCTIONS ] ===== //

function isLoggedIn(req, res, next)
{
    if (req.isAuthenticated()) next();
    else res.redirect(`/actuallylogin`);
}

function resetLocals(req, res, next)
{
    locals = {
        location: "",
        content: "",
        styles: [],
        scripts: [],
        user: req.user || null
    };
    next();
}

// ===== [ HTTP ROUTES ] ===== //

router.get("/dashboard", isLoggedIn, function(req, res)
{
    locals.location = "guilds";

    locals.guilds = [];
    for (let guild of req.user.guilds) {
        if (guild.owner || utils.determinePermissions(client.guilds.get(guild.id).members.get(req.user.id)) >= 300)
        {
            locals.guilds.push(client.guilds.get(guild.id));
        }
    }

    res.render("pages/dashboard", locals);
});

router.get("/dashboard/:guild", isLoggedIn, function(req, res)
{
    fs.readdir(join(__data, "guilds"), (err, guilds) => {
        if (err) console.error(err);

        if (guilds.indexOf(req.params.guild) > -1) locals.guild = client.guilds.get(req.params.guild);
        else return res.render("pages/error", { title: "404", content: "Applesauce! This guild cannot be found in the intergalactic databank!" });

        res.render("pages/dashboard", locals);
    });
});

router.get("/dashboard/:guild/users", isLoggedIn, function(req, res)
{
    locals.location = "users";

    fs.readdir(join(__data, "guilds"), (err, guilds) => {
        if (err) console.error(err);

        if (guilds.indexOf(req.params.guild) > -1) locals.members = client.guilds.get(req.params.guild).members.array();
        else return res.render("pages/error", { title: "404", content: "Applesauce! This guild cannot be found in the intergalactic databank!" });

        locals.guild = client.guilds.get(req.params.guild);

        res.render("pages/dashboard", locals);
    });
});

module.exports = router;
<commit_msg>handle POST requests<commit_after>const Discord = require("discord.js")
, express = require("express")
, passport = require("passport")
, Strategy = require("passport-discord").Strategy
, session = require("express-session")
, fs = require("fs-extra")
, join = require("path").join;

var router = express.Router()
, locals = {};

// ===== [ DISCORD AUTH ] ===== //

passport.serializeUser(function(user, done) {
    done(null, user);
});
passport.deserializeUser(function(obj, done) {
    done(null, obj);
});

passport.use(new Strategy({
    clientID: client.config.oauth.id,
    clientSecret: client.config.oauth.secret,
    callbackURL: client.config.oauth.callback,
    scope: ["identify", "guilds"]
}, function(accessToken, refreshToken, profile, done) {
    process.nextTick(function() {
        return done(null, profile);
    });
}));
router.use(session({
    secret: utils.genSecret(),
    resave: false,
    saveUninitialized: false
}));
router.use(passport.initialize());
router.use(passport.session());

router.get("/login", isLoggedIn, function(req, res)
{
    res.redirect("/dashboard");
});

router.get("/actuallylogin", passport.authenticate("discord", { scope: ["identify", "guilds"] }), (req, res) => {});

router.get("/callback", passport.authenticate("discord", { failureRedirect: "/" }), function(req, res)
{
    const userDir = join(__data, "users", req.user.id);

    fs.outputJson(`${userDir}/user.json`, req.user, (err) => {
        if (err) console.error(err);

        console.log("created " + userDir + "/user.json");
        res.redirect("/dashboard");
    });
});

router.get("/logout", function(req, res) {
    req.logout();
    res.redirect("/");
});

// ===== [ HELPER FUNCTIONS ] ===== //

function isLoggedIn(req, res, next)
{
    if (req.isAuthenticated()) next();
    else res.redirect(`/actuallylogin`);
}

function resetLocals(req, res, next)
{
    locals = {
        location: "",
        content: "",
        styles: [],
        scripts: [],
        user: req.user || null,
        guilds: []
    };
    if (req.user)
    {
        for (let guild of req.user.guilds) {
            if (guild.owner || (client.guilds.has(guild.id) && utils.determinePermissions(client.guilds.get(guild.id).members.get(req.user.id)) >= 300))
            {
                locals.guilds.push(client.guilds.get(guild.id));
            }
        }
    }
    next();
}

// ===== [ HTTP ROUTES ] ===== //

router.get("/dashboard", resetLocals, isLoggedIn, function(req, res)
{
    locals.location = "guilds";

    res.render("pages/dashboard", locals);
});

router.get("/dashboard/:guild", resetLocals, isLoggedIn, function(req, res)
{
    fs.readdir(join(__data, "guilds"), (err, guilds) => {
        if (err) console.error(err);

        if (guilds.indexOf(req.params.guild) === -1) return res.render("pages/error", Object.assign(locals, { location: "404", title: "404", content: "Applesauce! This guild cannot be found in the intergalactic databank!" }));

        locals.location = client.guilds.get(req.params.guild).name;
        locals.guild = client.guilds.get(req.params.guild);
        locals.members = locals.guild.members.array();

        locals.scripts.push("/i/dashboard/guild/js/guild.js");

        res.render("pages/dashboard", locals);
    });
});

router.post("/dashboard/:guild", resetLocals, isLoggedIn, function(req, res)
{
    let guild = client.guilds.get(req.params.guild);
    if (utils.determinePermissions(guild.members.get(req.user.id)) < 300) return res.status(401).send("Insufficient Permission.");

    console.log(req.body);
    if (req.body.name)
    {
        guild.setName(req.body.name).then(() => { res.status(200).end() });
    }

    else if (req.body.membersToKick && req.body.rolesToRemove)
    {
        let kicked = 0
        , removed = 0;

        for (let memberId of req.body.membersToKick) {
            kicked++;
            guild.members.get(memberId).kick();
        }

        for (let memberId in req.body.rolesToRemove) {
            removed++;
            guild.members.get(memberId).removeRoles(req.body.rolesToRemove[memberId]);
        }

        if (kicked === req.body.membersToKick.length && removed === Object.keys(req.body.rolesToRemove).length) res.status(200).end();
    }

    else if (req.body.enabled)
    {
        utils.readConfig(guild)
            .then(config => {
                config.rss.enabled = req.body.enabled;
                config.rss.feedURL = req.body.feedURL;
                config.rss.channel = req.body.channel;

                fs.outputJson(join(__data, "guilds", guild.id, "config.json"), config);

                res.redirect(req.originalUrl);
            }).catch(console.error);
    }
});

module.exports = router;
<|endoftext|>


<commit_before>const _ = require('lodash');
const countries = require('../../../config/countries');

module.exports = {
'expiry-year': {
  labelClassName: 'form-label',
  formatter: 'removehyphens',
    validate: [
        'numeric',
        'required'
    ]
},
'expiry-month': {
    labelClassName: 'form-label',
    formatter: 'removehyphens',
    validate: [
        'numeric',
        'required'
    ]
},
    'age-year': {
      labelClassName: 'form-label',
      formatter: 'removehyphens',
        validate: [
            'numeric',
            'required'
        ]
    },
    'age-month': {
        labelClassName: 'form-label',
        formatter: 'removehyphens',
        validate: [
            'numeric',
            'required'
        ]
    },
  'issuing-authority': {
    legend: {
      value: 'Which is your passport issuing authority?',
      className: 'visuallyhidden'
    },
    options: [
      {value: 'UKPA', label: 'UKPA'},
      {value: 'UKPS', label: 'UKPS'},
      {value: 'IPS', label: 'IPS'},
      {value: 'Other', label: 'Other'}
    ],
    validate: [
      'required'
    ]
  }
};
<commit_msg>Fix for the date of birth label<commit_after>const _ = require('lodash');
const countries = require('../../../config/countries');

module.exports = {
'expiry-year': {
  labelClassName: 'form-label',
  formatter: 'removehyphens',
    validate: [
        'numeric',
        'required'
    ]
},
'expiry-month': {
    labelClassName: 'form-label',
    formatter: 'removehyphens',
    validate: [
        'numeric',
        'required'
    ]
},
  'age-day': {
    labelClassName: 'form-label',
    formatter: 'removehyphens',
      validate: [
          'numeric',
          'required'
      ]
  },
  'age-year': {
    labelClassName: 'form-label',
    formatter: 'removehyphens',
      validate: [
          'numeric',
          'required'
      ]
  },
  'age-month': {
      labelClassName: 'form-label',
      formatter: 'removehyphens',
      validate: [
          'numeric',
          'required'
      ]
  },
  'issuing-authority': {
    legend: {
      value: 'Which is your passport issuing authority?',
      className: 'visuallyhidden'
    },
    options: [
      {value: 'UKPA', label: 'UKPA'},
      {value: 'UKPS', label: 'UKPS'},
      {value: 'IPS', label: 'IPS'},
      {value: 'Other', label: 'Other'}
    ],
    validate: [
      'required'
    ]
  }
};
<|endoftext|>