diff options
| author | 2014-07-19 02:38:53 +0200 | |
|---|---|---|
| committer | 2014-07-19 02:38:53 +0200 | |
| commit | 8446e16346ece5a934550f69e81d0cad528f7fba (patch) | |
| tree | a67e2564a6facbe9e307f619e5f98289009e6941 /module/web/themes/default/js/sources | |
| parent | Rename pyLoadCore as pyload and pyLoadCli as pyload-cli (diff) | |
| download | pyload-8446e16346ece5a934550f69e81d0cad528f7fba.tar.xz | |
New web structure + related code improvements and fixes + added flat and dark themes + updated js
Diffstat (limited to 'module/web/themes/default/js/sources')
| -rw-r--r-- | module/web/themes/default/js/sources/MooDialog.js | 140 | ||||
| -rw-r--r-- | module/web/themes/default/js/sources/MooDropMenu.js | 86 | ||||
| -rw-r--r-- | module/web/themes/default/js/sources/admin.coffee | 58 | ||||
| -rw-r--r-- | module/web/themes/default/js/sources/base.coffee | 173 | ||||
| -rw-r--r-- | module/web/themes/default/js/sources/filemanager.js | 291 | ||||
| -rw-r--r-- | module/web/themes/default/js/sources/package.js | 376 | ||||
| -rw-r--r-- | module/web/themes/default/js/sources/purr.js | 309 | ||||
| -rw-r--r-- | module/web/themes/default/js/sources/settings.coffee | 107 | ||||
| -rw-r--r-- | module/web/themes/default/js/sources/tinytab.js | 43 | 
9 files changed, 1583 insertions, 0 deletions
| diff --git a/module/web/themes/default/js/sources/MooDialog.js b/module/web/themes/default/js/sources/MooDialog.js new file mode 100644 index 000000000..45a52496f --- /dev/null +++ b/module/web/themes/default/js/sources/MooDialog.js @@ -0,0 +1,140 @@ +/* +--- +name: MooDialog +description: The base class of MooDialog +authors: Arian Stolwijk +license:  MIT-style license +requires: [Core/Class, Core/Element, Core/Element.Style, Core/Element.Event] +provides: [MooDialog, Element.MooDialog] +... +*/ + + +var MooDialog = new Class({ + +	Implements: [Options, Events], + +	options: { +		'class': 'MooDialog', +		title: null, +		scroll: true, // IE +		forceScroll: false, +		useEscKey: true, +		destroyOnHide: true, +		autoOpen: true, +		closeButton: true, +		onInitialize: function(){ +			this.wrapper.setStyle('display', 'none'); +		}, +		onBeforeOpen: function(){ +			this.wrapper.setStyle('display', 'block'); +			this.fireEvent('show'); +		}, +		onBeforeClose: function(){ +			this.wrapper.setStyle('display', 'none'); +			this.fireEvent('hide'); +		}/*, +		onOpen: function(){}, +		onClose: function(){}, +		onShow: function(){}, +		onHide: function(){}, +		onInitialize: function(wrapper){}, +		onContentChange: function(content){}*/ +	}, + +	initialize: function(options){ +		this.setOptions(options); +		this.options.inject = this.options.inject || document.body; +		options = this.options; + +		var wrapper = this.wrapper = new Element('div.' + options['class'].replace(' ', '.')).inject(options.inject); +		this.content = new Element('div.content').inject(wrapper); + +		if (options.title){ +			this.title = new Element('div.title').set('text', options.title).inject(wrapper); +			wrapper.addClass('MooDialogTitle'); +		} + +		if (options.closeButton){ +			this.closeButton = new Element('a.close', { +				events: {click: this.close.bind(this)} +			}).inject(wrapper); +		} + + +		/*<ie6>*/// IE 6 scroll +		if ((options.scroll && Browser.ie6) || options.forceScroll){ +			wrapper.setStyle('position', 'absolute'); +			var position = wrapper.getPosition(options.inject); +			window.addEvent('scroll', function(){ +				var scroll = document.getScroll(); +				wrapper.setPosition({ +					x: position.x + scroll.x, +					y: position.y + scroll.y +				}); +			}); +		} +		/*</ie6>*/ + +		if (options.useEscKey){ +			// Add event for the esc key +			document.addEvent('keydown', function(e){ +				if (e.key == 'esc') this.close(); +			}.bind(this)); +		} + +		this.addEvent('hide', function(){ +			if (options.destroyOnHide) this.destroy(); +		}.bind(this)); + +		this.fireEvent('initialize', wrapper); +	}, + +	setContent: function(){ +		var content = Array.from(arguments); +		if (content.length == 1) content = content[0]; + +		this.content.empty(); + +		var type = typeOf(content); +		if (['string', 'number'].contains(type)) this.content.set('text', content); +		else this.content.adopt(content); + +		this.fireEvent('contentChange', this.content); + +		return this; +	}, + +	open: function(){ +		this.fireEvent('beforeOpen', this.wrapper).fireEvent('open'); +		this.opened = true; +		return this; +	}, + +	close: function(){ +		this.fireEvent('beforeClose', this.wrapper).fireEvent('close'); +		this.opened = false; +		return this; +	}, + +	destroy: function(){ +		this.wrapper.destroy(); +	}, + +	toElement: function(){ +		return this.wrapper; +	} + +}); + + +Element.implement({ + +	MooDialog: function(options){ +		this.store('MooDialog', +			new MooDialog(options).setContent(this).open() +		); +		return this; +	} + +}); diff --git a/module/web/themes/default/js/sources/MooDropMenu.js b/module/web/themes/default/js/sources/MooDropMenu.js new file mode 100644 index 000000000..ac0fa1874 --- /dev/null +++ b/module/web/themes/default/js/sources/MooDropMenu.js @@ -0,0 +1,86 @@ +/* +--- +description: This provides a simple Drop Down menu with infinit levels + +license: MIT-style + +authors: +- Arian Stolwijk + +requires: +  - Core/Class.Extras +  - Core/Element.Event +  - Core/Selectors + +provides: [MooDropMenu, Element.MooDropMenu] + +... +*/ + +var MooDropMenu = new Class({ + +	Implements: [Options, Events], + +	options: { +		onOpen: function(el){ +			el.removeClass('close').addClass('open'); +		}, +		onClose: function(el){ +			el.removeClass('open').addClass('close'); +		}, +		onInitialize: function(el){ +			el.removeClass('open').addClass('close'); +		}, +		mouseoutDelay: 200, +		mouseoverDelay: 0, +		listSelector: 'ul', +		itemSelector: 'li', +		openEvent: 'mouseenter', +		closeEvent: 'mouseleave' +	}, + +	initialize: function(menu, options, level){ +		this.setOptions(options); +		options = this.options; + +		var menu = this.menu = document.id(menu); + +		menu.getElements(options.itemSelector + ' > ' + options.listSelector).each(function(el){ + +			this.fireEvent('initialize', el); + +			var parent = el.getParent(options.itemSelector), +				timer; + +			parent.addEvent(options.openEvent, function(){ +				parent.store('DropDownOpen', true); + +				clearTimeout(timer); +				if (options.mouseoverDelay) timer = this.fireEvent.delay(options.mouseoverDelay, this, ['open', el]); +				else this.fireEvent('open', el); + +			}.bind(this)).addEvent(options.closeEvent, function(){ +				parent.store('DropDownOpen', false); + +				clearTimeout(timer); +				timer = (function(){ +					if (!parent.retrieve('DropDownOpen')) this.fireEvent('close', el); +				}).delay(options.mouseoutDelay, this); + +			}.bind(this)); + +		}, this); +	}, + +	toElement: function(){ +		return this.menu +	} + +}); + +/* So you can do like this $('nav').MooDropMenu(); or even $('nav').MooDropMenu().setStyle('border',1); */ +Element.implement({ +	MooDropMenu: function(options){ +		return this.store('MooDropMenu', new MooDropMenu(this, options)); +	} +}); diff --git a/module/web/themes/default/js/sources/admin.coffee b/module/web/themes/default/js/sources/admin.coffee new file mode 100644 index 000000000..c4ab86911 --- /dev/null +++ b/module/web/themes/default/js/sources/admin.coffee @@ -0,0 +1,58 @@ +root = this + +window.addEvent "domready", -> + +    root.passwordDialog = new MooDialog {destroyOnHide: false} +    root.passwordDialog.setContent $ 'password_box' + +    $("login_password_reset").addEvent "click", (e) -> root.passwordDialog.close() +    $("login_password_button").addEvent "click", (e) -> + +        newpw = $("login_new_password").get("value") +        newpw2 = $("login_new_password2").get("value") + +        if newpw is newpw2 +            form = $("password_form") +            form.set "send", { +                onSuccess: (data) -> +                    root.notify.alert "Success", { +                            'className': 'success' +                        } +                onFailure: (data) -> +                    root.notify.alert "Error", { +                            'className': 'error' +                        } +                } + +            form.send() + +            root.passwordDialog.close() +        else +            alert '{{_("Passwords did not match.")}}' + +        e.stop() + +    for item in $$(".change_password") +        id = item.get("id") +        user = id.split("|")[1] +        $("user_login").set("value", user) +        item.addEvent "click", (e) -> root.passwordDialog.open() + +    $('quit-pyload').addEvent "click", (e) -> +        new MooDialog.Confirm "{{_('You are really sure you want to quit pyLoad?')}}", -> +            new Request.JSON({ +                url: '/api/kill' +                method: 'get' +            }).send() +        , -> +        e.stop() + +    $('restart-pyload').addEvent "click", (e) -> +        new MooDialog.Confirm "{{_('Are you sure you want to restart pyLoad?')}}", -> +            new Request.JSON({ +                url: '/api/restart' +                method: 'get' +                onSuccess: (data) -> alert "{{_('pyLoad restarted')}}" +            }).send() +        , -> +        e.stop() diff --git a/module/web/themes/default/js/sources/base.coffee b/module/web/themes/default/js/sources/base.coffee new file mode 100644 index 000000000..55151acc9 --- /dev/null +++ b/module/web/themes/default/js/sources/base.coffee @@ -0,0 +1,173 @@ +# External scope +root = this + +# helper functions +humanFileSize = (size) -> +    filesizename = new Array("B", "KiB", "MiB", "GiB", "TiB", "PiB") +    loga = Math.log(size) / Math.log(1024) +    i = Math.floor(loga) +    a = Math.pow(1024, i) +    if size is 0 then "0 B" else (Math.round(size * 100 / a) / 100 + " " + filesizename[i]) + +parseUri = () -> +    oldString = $("add_links").value +    regxp = new RegExp('(ht|f)tp(s?):\/\/[a-zA-Z0-9\-\.\/\?=_&%#]+[<| |\"|\'|\r|\n|\t]{1}', 'g') +    resu = oldString.match regxp +    return if resu == null +    res = ""; + +    for part in resu +        if part.indexOf(" ") != -1 +            res = res + part.replace(" ", " \n") +        else if part.indexOf("\t") != -1 +            res = res + part.replace("\t", " \n") +        else if part.indexOf("\r") != -1 +            res = res + part.replace("\r", " \n") +        else if part.indexOf("\"") != -1 +            res = res + part.replace("\"", " \n") +        else if part.indexOf("<") != -1 +            res = res + part.replace("<", " \n") +        else if part.indexOf("'") != -1 +            res = res + part.replace("'", " \n") +        else +            res = res + part.replace("\n", " \n") + +    $("add_links").value = res; + + +Array::remove = (from, to) -> +    rest = this.slice((to || from) + 1 || this.length) +    this.length = from < 0 ? this.length + from : from +    return [] if this.length == 0 +    return this.push.apply(this, rest) + + +document.addEvent "domready", -> + +    # global notification +    root.notify = new Purr { +        'mode': 'top' +        'position': 'center' +    } + +    root.captchaBox = new MooDialog {destroyOnHide: false} +    root.captchaBox.setContent $ 'cap_box' + +    root.addBox = new MooDialog {destroyOnHide: false} +    root.addBox.setContent $ 'add_box' + +    $('add_form').onsubmit = -> +        $('add_form').target = 'upload_target' +        if $('add_name').value is "" and $('add_file').value is "" +            alert '{{_("Please Enter a packagename.")}}' +            return false +        else +            root.addBox.close() +            return true + +    $('add_reset').addEvent 'click', -> root.addBox.close() + +    $('action_add').addEvent 'click', -> $("add_form").reset(); root.addBox.open() +    $('action_play').addEvent 'click', -> new Request({method: 'get', url: '/api/unpauseServer'}).send() +    $('action_cancel').addEvent 'click', -> new Request({method: 'get', url: '/api/stopAllDownloads'}).send() +    $('action_stop').addEvent 'click', -> new Request({method: 'get', url: '/api/pauseServer'}).send() + + +    # captcha events + +    $('cap_info').addEvent 'click', -> +        load_captcha "get", "" +        root.captchaBox.open() +    $('cap_reset').addEvent 'click', -> root.captchaBox.close() +    $('cap_form').addEvent 'submit', (e) -> +        submit_captcha() +        e.stop() + +    $('cap_positional').addEvent 'click', on_captcha_click + +    new Request.JSON({ +        url: "/json/status" +        onSuccess: LoadJsonToContent +        secure: false +        async: true +        initialDelay: 0 +        delay: 4000 +        limit: 3000 +    }).startTimer() + +LoadJsonToContent = (data) -> +    $("speed").set 'text', humanFileSize(data.speed)+"/s" +    $("aktiv").set 'text', data.active +    $("aktiv_from").set 'text', data.queue +    $("aktiv_total").set 'text', data.total + +    if data.captcha +        if $("cap_info").getStyle("display") != "inline" +            $("cap_info").setStyle 'display', 'inline' +            root.notify.alert '{{_("New Captcha Request")}}', { +                            'className': 'notify' +                        } +    else +        $("cap_info").setStyle 'display', 'none' + + +    if data.download +        $("time").set 'text', ' {{_("on")}}' +        $("time").setStyle 'background-color', "#8ffc25" +    else +        $("time").set 'text', ' {{_("off")}}' +        $("time").setStyle 'background-color', "#fc6e26" + +    if data.reconnect +        $("reconnect").set 'text', ' {{_("on")}}' +        $("reconnect").setStyle 'background-color', "#8ffc25" +    else +        $("reconnect").set 'text', ' {{_("off")}}' +        $("reconnect").setStyle 'background-color', "#fc6e26" + +    return null + + +set_captcha = (data) -> +    $('cap_id').set 'value', data.id +    if (data.result_type is 'textual') +        $('cap_textual_img').set 'src', data.src +        $('cap_title').set 'text', '{{_("Please read the text on the captcha.")}}' +        $('cap_submit').setStyle 'display', 'inline' +        $('cap_textual').setStyle 'display', 'block' +        $('cap_positional').setStyle 'display', 'none' + +    else if (data.result_type == 'positional') +        $('cap_positional_img').set('src', data.src) +        $('cap_title').set('text', '{{_("Please click on the right captcha position.")}}') +        $('cap_submit').setStyle('display', 'none') +        $('cap_textual').setStyle('display', 'none') + + +load_captcha = (method, post) -> +    new Request.JSON({ +        url: "/json/set_captcha" +        onSuccess: (data) -> set_captcha(data) if data.captcha else clear_captcha() +        secure: false +        async: true +        method: method +    }).send(post) + +clear_captcha = -> +    $('cap_textual').setStyle 'display', 'none' +    $('cap_textual_img').set 'src', '' +    $('cap_positional').setStyle 'display', 'none' +    $('cap_positional_img').set 'src', '' +    $('cap_title').set 'text', '{{_("No Captchas to read.")}}' + +submit_captcha = -> +    load_captcha("post", "cap_id=" + $('cap_id').get('value') + "&cap_result=" + $('cap_result').get('value') ); +    $('cap_result').set('value', '') +    false + +on_captcha_click = (e) ->  +    position = e.target.getPosition() +    x = e.page.x - position.x +    y = e.page.y - position.y +    $('cap_result').value = x + "," + y +    submit_captcha() diff --git a/module/web/themes/default/js/sources/filemanager.js b/module/web/themes/default/js/sources/filemanager.js new file mode 100644 index 000000000..be2f51e13 --- /dev/null +++ b/module/web/themes/default/js/sources/filemanager.js @@ -0,0 +1,291 @@ +var load, rename_box, confirm_box; + +document.addEvent("domready", function() { +    load = new Fx.Tween($("load-indicator"), {link: "cancel"}); +    load.set("opacity", 0); + +    rename_box = new Fx.Tween($('rename_box')); +    confirm_box = new Fx.Tween($('confirm_box')); +    $('rename_reset').addEvent('click', function() { +        hide_rename_box() +    }); +    $('delete_reset').addEvent('click', function() { +        hide_confirm_box() +    }); + +    /*$('filemanager_actions_list').getChildren("li").each(function(action) { +      var action_name = action.className; +      if(functions[action.className] != undefined) +      { +	action.addEvent('click', functions[action.className]); +      } +    });*/ +}); + +function indicateLoad() { +    //$("load-indicator").reveal(); +    load.start("opacity", 1) +} + +function indicateFinish() { +    load.start("opacity", 0) +} + +function indicateSuccess() { +    indicateFinish(); +    notify.alert('{{_("Success")}}.', { +             'className': 'success' +    }); +} + +function indicateFail() { +    indicateFinish(); +    notify.alert('{{_("Failed")}}.', { +             'className': 'error' +    }); +} + +function show_rename_box() { +    bg_show(); +    $("rename_box").setStyle('display', 'block'); +    rename_box.start('opacity', 1) +} + +function hide_rename_box() { +    bg_hide(); +    rename_box.start('opacity', 0).chain(function() { +        $('rename_box').setStyle('display', 'none'); +    }); +} + +function show_confirm_box() { +    bg_show(); +    $("confirm_box").setStyle('display', 'block'); +    confirm_box.start('opacity', 1) +} + +function hide_confirm_box() { +    bg_hide(); +    confirm_box.start('opacity', 0).chain(function() { +        $('confirm_box').setStyle('display', 'none'); +    }); +} + +var FilemanagerUI = new Class({ +    initialize: function(url, type) { +        this.url = url; +        this.type = type; +        this.directories = []; +	this.files = []; +        this.parseChildren(); +    }, + +    parseChildren: function() { +        $("directories-list").getChildren("li.folder").each(function(ele) { +            var path = ele.getElements("input.path")[0].get("value"); +            var name = ele.getElements("input.name")[0].get("value"); +            this.directories.push(new Item(this, path, name, ele)) +        }.bind(this)); +	 +	$("directories-list").getChildren("li.file").each(function(ele) { +            var path = ele.getElements("input.path")[0].get("value"); +            var name = ele.getElements("input.name")[0].get("value"); +            this.files.push(new Item(this, path, name, ele)) +        }.bind(this)); +    } +}); + +var Item = new Class({ +    initialize: function(ui, path, name, ele) { +        this.ui = ui; +	this.path = path; +	this.name = name; +        this.ele = ele; +	this.directories = []; +	this.files = []; +	this.actions = new Array(); +	this.actions["delete"] = this.del; +	this.actions["rename"] = this.rename; +	this.actions["mkdir"] = this.mkdir; +        this.parseElement(); + +        var pname = this.ele.getElements("span")[0]; +        this.buttons = new Fx.Tween(this.ele.getElements(".buttons")[0], {link: "cancel"}); +        this.buttons.set("opacity", 0); + +        pname.addEvent("mouseenter", function(e) { +            this.buttons.start("opacity", 1) +        }.bind(this)); + +        pname.addEvent("mouseleave", function(e) { +            this.buttons.start("opacity", 0) +        }.bind(this)); + +    }, + +    parseElement: function() { +        this.ele.getChildren('span span.buttons img').each(function(img) { +	  img.addEvent('click', this.actions[img.className].bind(this)); +	}, this); + +	//click on the directory name must open the directory itself +	this.ele.getElements('b')[0].addEvent('click', this.toggle.bind(this)); +	 +	//iterate over child directories +	var uls = this.ele.getElements('ul'); +	if(uls.length > 0) +	{ +	  uls[0].getChildren("li.folder").each(function(fld) { +	    var path = fld.getElements("input.path")[0].get("value"); +	    var name = fld.getElements("input.name")[0].get("value"); +	    this.directories.push(new Item(this, path, name, fld)); +	  }.bind(this)); +	  uls[0].getChildren("li.file").each(function(fld) { +	    var path = fld.getElements("input.path")[0].get("value"); +	    var name = fld.getElements("input.name")[0].get("value"); +	    this.files.push(new Item(this, path, name, fld)); +	  }.bind(this)); +	} +    }, + +    reorderElements: function() { +      //TODO sort the main ul again (to keep data ordered after renaming something) +    }, + +    del: function(event) { +        $("confirm_form").removeEvents("submit"); +        $("confirm_form").addEvent("submit", this.deleteDirectory.bind(this)); + +	$$("#confirm_form p").set('html', '{{_(("Are you sure you want to delete the selected item?"))}}'); +	 +        show_confirm_box(); +        event.stop(); +    }, + +    deleteDirectory: function(event) { +        hide_confirm_box(); +	new Request.JSON({ +            method: 'POST', +            url: "/json/filemanager/delete", +	    data: {"path": this.path, "name": this.name}, +            onSuccess: function(data) { +		if(data.response == "success") +		{ +		  new Fx.Tween(this.ele).start('opacity', 0); +		  var ul = this.ele.parentNode; +		  this.ele.dispose(); +		  //if this was the only child, add a "empty folder" div +		  if(!ul.getChildren('li')[0]) +		  { +		    var div = new Element("div", { 'html': '{{ _("Folder is empty") }}' }); +		    div.replaces(ul); +		  } + +		  indicateSuccess(); +		} else +		{ +		  //error from json code... +		  indicateFail(); +		} +            }.bind(this), +            onFailure: indicateFail +        }).send(); +	 +        event.stop(); +    }, + +    rename: function(event) { +        $("rename_form").removeEvents("submit"); +        $("rename_form").addEvent("submit", this.renameDirectory.bind(this)); + +	$("path").set("value", this.path); +        $("old_name").set("value", this.name); +        $("new_name").set("value", this.name); + +        show_rename_box(); +        event.stop(); +    }, + +    renameDirectory: function(event) { +        hide_rename_box(); +	new Request.JSON({ +            method: 'POST', +            url: "/json/filemanager/rename", +            onSuccess: function(data) { +		if(data.response == "success") +		{ +		  this.name = $("new_name").get("value"); +		  this.ele.getElements("b")[0].set('html', $("new_name").get("value")); +		  this.reorderElements(); +		  indicateSuccess(); +		} else +		{ +		  //error from json code... +		  indicateFail(); +		} +            }.bind(this), +            onFailure: indicateFail +        }).send($("rename_form").toQueryString()); +	 +        event.stop(); +    }, + +    mkdir: function(event) { +      new Request.JSON({ +	  method: 'POST', +	  url: "/json/filemanager/mkdir", +	  data: {"path": this.path + "/" + this.name, "name": '{{_("New folder")}}'}, +	  onSuccess: function(data) { +	      if(data.response == "success") +	      { +		new Request.HTML({ +		    method: 'POST', +		    url: "/filemanager/get_dir", +		    data: {"path": data.path, "name": data.name}, +		    onSuccess: function(li) { +			//add node as first child of ul +			var ul = this.ele.getChildren('ul')[0]; +			if(!ul) +			{ +			  //remove the "Folder Empty" div +			  this.ele.getChildren('div').dispose(); + +			  //create new ul to contain subfolder +			  ul = new Element("ul"); +			  ul.inject(this.ele, 'bottom'); +			} +			li[0].inject(ul, 'top'); +			 +			//add directory as a subdirectory of the current item +			this.directories.push(new Item(this.ui, data.path, data.name, ul.firstChild)); +		    }.bind(this), +		    onFailure: indicateFail +		}).send(); +		indicateSuccess(); +	      } else +	      { +		//error from json code... +		indicateFail(); +	      } +	  }.bind(this), +	  onFailure: indicateFail +      }).send(); + +      event.stop(); +    }, + +    toggle: function() { +        var child = this.ele.getElement('ul'); +	if(child == null) +	  child = this.ele.getElement('div'); +	 +	if(child != null) +	{ +	  if (child.getStyle('display') == "block") { +	      child.dissolve(); +	  } else { +	      child.reveal(); +	  } +	} +    } +}); diff --git a/module/web/themes/default/js/sources/package.js b/module/web/themes/default/js/sources/package.js new file mode 100644 index 000000000..5d0ecbd3e --- /dev/null +++ b/module/web/themes/default/js/sources/package.js @@ -0,0 +1,376 @@ +var root = this; + +document.addEvent("domready", function() { +    root.load = new Fx.Tween($("load-indicator"), {link: "cancel"}); +    root.load.set("opacity", 0); + + +    root.packageBox = new MooDialog({destroyOnHide: false}); +    root.packageBox.setContent($('pack_box')); + +    $('pack_reset').addEvent('click', function() { +        $('pack_form').reset(); +        root.packageBox.close(); +    }); +}); + +function indicateLoad() { +    //$("load-indicator").reveal(); +    root.load.start("opacity", 1) +} + +function indicateFinish() { +    root.load.start("opacity", 0) +} + +function indicateSuccess() { +    indicateFinish(); +    root.notify.alert('{{_("Success")}}.', { +             'className': 'success' +    }); +} + +function indicateFail() { +    indicateFinish(); +    root.notify.alert('{{_("Failed")}}.', { +             'className': 'error' +    }); +} + +var PackageUI = new Class({ +    initialize: function(url, type) { +        this.url = url; +        this.type = type; +        this.packages = []; +        this.parsePackages(); + +        this.sorts = new Sortables($("package-list"), { +            constrain: false, +            clone: true, +            revert: true, +            opacity: 0.4, +            handle: ".package_drag", +            onComplete: this.saveSort.bind(this) +        }); + +        $("del_finished").addEvent("click", this.deleteFinished.bind(this)); +        $("restart_failed").addEvent("click", this.restartFailed.bind(this)); + +    }, + +    parsePackages: function() { +        $("package-list").getChildren("li").each(function(ele) { +            var id = ele.getFirst().get("id").match(/[0-9]+/); +            this.packages.push(new Package(this, id, ele)) +        }.bind(this)) +    }, + +    loadPackages: function() { +    }, + +    deleteFinished: function() { +        indicateLoad(); +        new Request.JSON({ +            method: 'get', +            url: '/api/deleteFinished', +            onSuccess: function(data) { +                if (data.length > 0) { +                    window.location.reload() +                } else { +                    this.packages.each(function(pack) { +                        pack.close(); +                    }); +                    indicateSuccess(); +                } +            }.bind(this), +            onFailure: indicateFail +        }).send(); +    }, + +    restartFailed: function() { +        indicateLoad(); +        new Request.JSON({ +            method: 'get', +            url: '/api/restartFailed', +            onSuccess: function(data) { +                this.packages.each(function(pack) { +                    pack.close(); +                }); +                indicateSuccess(); +            }.bind(this), +            onFailure: indicateFail +        }).send(); +    }, + +    startSort: function(ele, copy) { +    }, + +    saveSort: function(ele, copy) { +        var order = []; +        this.sorts.serialize(function(li, pos) { +            if (li == ele && ele.retrieve("order") != pos) { +                order.push(ele.retrieve("pid") + "|" + pos) +            } +            li.store("order", pos) +        }); +        if (order.length > 0) { +            indicateLoad(); +            new Request.JSON({ +                method: 'get', +                url: '/json/package_order/' + order[0], +                onSuccess: indicateFinish, +                onFailure: indicateFail +            }).send(); +        } +    } + +}); + +var Package = new Class({ +    initialize: function(ui, id, ele, data) { +        this.ui = ui; +        this.id = id; +        this.linksLoaded = false; + +        if (!ele) { +            this.createElement(data); +        } else { +            this.ele = ele; +            this.order = ele.getElements("div.order")[0].get("html"); +            this.ele.store("order", this.order); +            this.ele.store("pid", this.id); +            this.parseElement(); +        } + +        var pname = this.ele.getElements(".packagename")[0]; +        this.buttons = new Fx.Tween(this.ele.getElements(".buttons")[0], {link: "cancel"}); +        this.buttons.set("opacity", 0); + +        pname.addEvent("mouseenter", function(e) { +            this.buttons.start("opacity", 1) +        }.bind(this)); + +        pname.addEvent("mouseleave", function(e) { +            this.buttons.start("opacity", 0) +        }.bind(this)); + + +    }, + +    createElement: function() { +        alert("create") +    }, + +    parseElement: function() { +        var imgs = this.ele.getElements('img'); + +        this.name = this.ele.getElements('.name')[0]; +        this.folder = this.ele.getElements('.folder')[0]; +        this.password = this.ele.getElements('.password')[0]; + +        imgs[1].addEvent('click', this.deletePackage.bind(this)); +        imgs[2].addEvent('click', this.restartPackage.bind(this)); +        imgs[3].addEvent('click', this.editPackage.bind(this)); +        imgs[4].addEvent('click', this.movePackage.bind(this)); + +        this.ele.getElement('.packagename').addEvent('click', this.toggle.bind(this)); + +    }, + +    loadLinks: function() { +        indicateLoad(); +        new Request.JSON({ +            method: 'get', +            url: '/json/package/' + this.id, +            onSuccess: this.createLinks.bind(this), +            onFailure: indicateFail +        }).send(); +    }, + +    createLinks: function(data) { +        var ul = $("sort_children_{id}".substitute({"id": this.id})); +        ul.set("html", ""); +        data.links.each(function(link) { +            link.id = link.fid; +            var li = new Element("li", { +                "style": { +                    "margin-left": 0 +                } +            }); + +            var html = "<span style='cursor: move' class='child_status sorthandle'><img src='../img/{icon}' style='width: 12px; height:12px;'/></span>\n".substitute({"icon": link.icon}); +            html += "<span style='font-size: 15px'><a href=\"{url}\" target=\"_blank\">{name}</a></span><br /><div class='child_secrow'>".substitute({"url": link.url, "name": link.name}); +            html += "<span class='child_status'>{statusmsg}</span>{error} ".substitute({"statusmsg": link.statusmsg, "error":link.error}); +            html += "<span class='child_status'>{format_size}</span>".substitute({"format_size": link.format_size}); +            html += "<span class='child_status'>{plugin}</span>  ".substitute({"plugin": link.plugin}); +            html += "<img title='{{_(\"Delete Link\")}}' style='cursor: pointer;' width='10px' height='10px' src='../img/delete.png' />  "; +            html += "<img title='{{_(\"Restart Link\")}}' style='cursor: pointer;margin-left: -4px' width='10px' height='10px' src='../img/arrow_refresh.png' /></div>"; + +            var div = new Element("div", { +                "id": "file_" + link.id, +                "class": "child", +                "html": html +            }); + +            li.store("order", link.order); +            li.store("lid", link.id); + +            li.adopt(div); +            ul.adopt(li); +        }); +        this.sorts = new Sortables(ul, { +            constrain: false, +            clone: true, +            revert: true, +            opacity: 0.4, +            handle: ".sorthandle", +            onComplete: this.saveSort.bind(this) +        }); +        this.registerLinkEvents(); +        this.linksLoaded = true; +        indicateFinish(); +        this.toggle(); +    }, + +    registerLinkEvents: function() { +        this.ele.getElements('.child').each(function(child) { +            var lid = child.get('id').match(/[0-9]+/); +            var imgs = child.getElements('.child_secrow img'); +            imgs[0].addEvent('click', function(e) { +                new Request({ +                    method: 'get', +                    url: '/api/deleteFiles/[' + this + "]", +                    onSuccess: function() { +                        $('file_' + this).nix() +                    }.bind(this), +                    onFailure: indicateFail +                }).send(); +            }.bind(lid)); + +            imgs[1].addEvent('click', function(e) { +                new Request({ +                    method: 'get', +                    url: '/api/restartFile/' + this, +                    onSuccess: function() { +                        var ele = $('file_' + this); +                        var imgs = ele.getElements("img"); +                        imgs[0].set("src", "../img/status_queue.png"); +                        var spans = ele.getElements(".child_status"); +                        spans[1].set("html", "queued"); +                        indicateSuccess(); +                    }.bind(this), +                    onFailure: indicateFail +                }).send(); +            }.bind(lid)); +        }); +    }, + +    toggle: function() { +        var child = this.ele.getElement('.children'); +        if (child.getStyle('display') == "block") { +            child.dissolve(); +        } else { +            if (!this.linksLoaded) { +                this.loadLinks(); +            } else { +                child.reveal(); +            } +        } +    }, + + +    deletePackage: function(event) { +        indicateLoad(); +        new Request({ +            method: 'get', +            url: '/api/deletePackages/[' + this.id + "]", +            onSuccess: function() { +                this.ele.nix(); +                indicateFinish(); +            }.bind(this), +            onFailure: indicateFail +        }).send(); +        //hide_pack(); +        event.stop(); +    }, + +    restartPackage: function(event) { +        indicateLoad(); +        new Request({ +            method: 'get', +            url: '/api/restartPackage/' + this.id, +            onSuccess: function() { +                this.close(); +                indicateSuccess(); +            }.bind(this), +            onFailure: indicateFail +        }).send(); +        event.stop(); +    }, + +    close: function() { +        var child = this.ele.getElement('.children'); +        if (child.getStyle('display') == "block") { +            child.dissolve(); +        } +        var ul = $("sort_children_{id}".substitute({"id": this.id})); +        ul.erase("html"); +        this.linksLoaded = false; +    }, + +    movePackage: function(event) { +        indicateLoad(); +        new Request({ +            method: 'get', +            url: '/json/move_package/' + ((this.ui.type + 1) % 2) + "/" + this.id, +            onSuccess: function() { +                this.ele.nix(); +                indicateFinish(); +            }.bind(this), +            onFailure: indicateFail +        }).send(); +        event.stop(); +    }, + +    editPackage: function(event) { +        $("pack_form").removeEvents("submit"); +        $("pack_form").addEvent("submit", this.savePackage.bind(this)); + +        $("pack_id").set("value", this.id); +        $("pack_name").set("value", this.name.get("text")); +        $("pack_folder").set("value", this.folder.get("text")); +        $("pack_pws").set("value", this.password.get("text")); + +        root.packageBox.open(); +        event.stop(); +    }, + +    savePackage: function(event) { +        $("pack_form").send(); +        this.name.set("text", $("pack_name").get("value")); +        this.folder.set("text", $("pack_folder").get("value")); +        this.password.set("text", $("pack_pws").get("value")); +        root.packageBox.close(); +        event.stop(); +    }, + +    saveSort: function(ele, copy) { +        var order = []; +        this.sorts.serialize(function(li, pos) { +            if (li == ele && ele.retrieve("order") != pos) { +                order.push(ele.retrieve("lid") + "|" + pos) +            } +            li.store("order", pos) +        }); +        if (order.length > 0) { +            indicateLoad(); +            new Request.JSON({ +                method: 'get', +                url: '/json/link_order/' + order[0], +                onSuccess: indicateFinish, +                onFailure: indicateFail +            }).send(); +        } +    } + +}); diff --git a/module/web/themes/default/js/sources/purr.js b/module/web/themes/default/js/sources/purr.js new file mode 100644 index 000000000..9cbc503d9 --- /dev/null +++ b/module/web/themes/default/js/sources/purr.js @@ -0,0 +1,309 @@ +/* +--- +script: purr.js + +description: Class to create growl-style popup notifications. + +license: MIT-style + +authors: [atom smith] + +requires: +- core/1.3: [Core, Browser, Array, Function, Number, String, Hash, Event, Class.Extras, Element.Event, Element.Style, Element.Dimensions, Fx.CSS, FX.Tween, Fx.Morph] + +provides: [Purr, Element.alert] +... +*/ + + +var Purr = new Class({ + +	'options': { +		'mode': 'top', +		'position': 'left', +		'elementAlertClass': 'purr-element-alert', +		'elements': { +			'wrapper': 'div', +			'alert': 'div', +			'buttonWrapper': 'div', +			'button': 'button' +		}, +		'elementOptions': { +			'wrapper': { +				'styles': { +					'position': 'fixed', +					'z-index': '9999' +				}, +				'class': 'purr-wrapper' +			}, +			'alert': { +				'class': 'purr-alert', +				'styles': { +					'opacity': '.85' +				} +			}, +			'buttonWrapper': { +				'class': 'purr-button-wrapper' +			}, +			'button': { +				'class': 'purr-button' +			} +		}, +		'alert': { +			'buttons': [], +			'clickDismiss': true, +			'hoverWait': true, +			'hideAfter': 5000, +			'fx': { +				'duration': 500 +			}, +			'highlight': false, +			'highlightRepeat': false, +			'highlight': { +				'start': '#FF0', +				'end': false +			} +		} +	}, + +	'Implements': [Options, Events, Chain], + +	'initialize': function(options){ +		this.setOptions(options); +		this.createWrapper(); +		return this; +	}, + +	'bindAlert': function(){ +		return this.alert.bind(this); +	}, + +	'createWrapper': function(){ +		this.wrapper = new Element(this.options.elements.wrapper, this.options.elementOptions.wrapper); +		if(this.options.mode == 'top') +		{ +			this.wrapper.setStyle('top', 0); +		} +		else +		{ +			this.wrapper.setStyle('bottom', 0); +		} +		document.id(document.body).grab(this.wrapper); +		this.positionWrapper(this.options.position); +	}, + +	'positionWrapper': function(position){ +		if(typeOf(position) == 'object') +		{ + +			var wrapperCoords = this.getWrapperCoords(); + +			this.wrapper.setStyles({ +				'bottom': '', +				'left': position.x, +				'top': position.y - wrapperCoords.height, +				'position': 'absolute' +			}); +		} +		else if(position == 'left') +		{ +			this.wrapper.setStyle('left', 0); +		} +		else if(position == 'right') +		{ +			this.wrapper.setStyle('right', 0); +		} +		else +		{ +			this.wrapper.setStyle('left', (window.innerWidth / 2) - (this.getWrapperCoords().width / 2)); +		} +		return this; +	}, + +	'getWrapperCoords': function(){ +		this.wrapper.setStyle('visibility', 'hidden'); +		var measurer = this.alert('need something in here to measure'); +		var coords = this.wrapper.getCoordinates(); +		measurer.destroy(); +		this.wrapper.setStyle('visibility',''); +		return coords; +	}, + +	'alert': function(msg, options){ + +		options = Object.merge({}, this.options.alert, options || {}); + +		var alert = new Element(this.options.elements.alert, this.options.elementOptions.alert); + +		if(typeOf(msg) == 'string') +		{ +			alert.set('html', msg); +		} +		else if(typeOf(msg) == 'element') +		{ +			alert.grab(msg); +		} +		else if(typeOf(msg) == 'array') +		{ +			var alerts = []; +			msg.each(function(m){ +				alerts.push(this.alert(m, options)); +			}, this); +			return alerts; +		} + +		alert.store('options', options); + +		if(options.buttons.length > 0) +		{ +			options.clickDismiss = false; +			options.hideAfter = false; +			options.hoverWait = false; +			var buttonWrapper = new Element(this.options.elements.buttonWrapper, this.options.elementOptions.buttonWrapper); +			alert.grab(buttonWrapper); +			options.buttons.each(function(button){ +				if(button.text != undefined) +				{ +					var callbackButton = new Element(this.options.elements.button, this.options.elementOptions.button); +					callbackButton.set('html', button.text); +					if(button.callback != undefined) +					{ +						callbackButton.addEvent('click', button.callback.pass(alert)); +					} +					if(button.dismiss != undefined && button.dismiss) +					{ +						callbackButton.addEvent('click', this.dismiss.pass(alert, this)); +					} +					buttonWrapper.grab(callbackButton); +				} +			}, this); +		} +		if(options.className != undefined) +		{ +			alert.addClass(options.className); +		} + +		this.wrapper.grab(alert, (this.options.mode == 'top') ? 'bottom' : 'top'); + +		var fx = Object.merge(this.options.alert.fx, options.fx); +		var alertFx = new Fx.Morph(alert, fx); +		alert.store('fx', alertFx); +		this.fadeIn(alert); + +		if(options.highlight) +		{ +			alertFx.addEvent('complete', function(){ +				alert.highlight(options.highlight.start, options.highlight.end); +				if(options.highlightRepeat) +				{ +					alert.highlight.periodical(options.highlightRepeat, alert, [options.highlight.start, options.highlight.end]); +				} +			}); +		} +		if(options.hideAfter) +		{ +			this.dismiss(alert); +		} + +		if(options.clickDismiss) +		{ +			alert.addEvent('click', function(){ +				this.holdUp = false; +				this.dismiss(alert, true); +			}.bind(this)); +		} + +		if(options.hoverWait) +		{ +			alert.addEvents({ +				'mouseenter': function(){ +					this.holdUp = true; +				}.bind(this), +				'mouseleave': function(){ +					this.holdUp = false; +				}.bind(this) +			}); +		} + +		return alert; +	}, + +	'fadeIn': function(alert){ +		var alertFx = alert.retrieve('fx'); +		alertFx.set({ +			'opacity': 0 +		}); +		alertFx.start({ +			'opacity': [this.options.elementOptions.alert.styles.opacity, .9].pick(), +		}); +	}, + +	'dismiss': function(alert, now){ +		now = now || false; +		var options = alert.retrieve('options'); +		if(now) +		{ +			this.fadeOut(alert); +		} +		else +		{ +			this.fadeOut.delay(options.hideAfter, this, alert); +		} +	}, + +	'fadeOut': function(alert){ +		if(this.holdUp) +		{ +			this.dismiss.delay(100, this, [alert, true]) +			return null; +		} +		var alertFx = alert.retrieve('fx'); +		if(!alertFx) +		{ +			return null; +		} +		var to = { +			'opacity': 0 +		} +		if(this.options.mode == 'top') +		{ +			to['margin-top'] = '-'+alert.offsetHeight+'px'; +		} +		else +		{ +			to['margin-bottom'] = '-'+alert.offsetHeight+'px'; +		} +		alertFx.start(to); +		alertFx.addEvent('complete', function(){ +			alert.destroy(); +		}); +	} +}); + +Element.implement({ + +	'alert': function(msg, options){ +		var alert = this.retrieve('alert'); +		if(!alert) +		{ +			options = options || { +				'mode':'top' +			}; +			alert = new Purr(options) +			this.store('alert', alert); +		} + +		var coords = this.getCoordinates(); + +		alert.alert(msg, options); + +		alert.wrapper.setStyles({ +			'bottom': '', +			'left': (coords.left - (alert.wrapper.getWidth() / 2)) + (this.getWidth() / 2), +			'top': coords.top - (alert.wrapper.getHeight()), +			'position': 'absolute' +		}); + +	} + +});
\ No newline at end of file diff --git a/module/web/themes/default/js/sources/settings.coffee b/module/web/themes/default/js/sources/settings.coffee new file mode 100644 index 000000000..68ca6c6a0 --- /dev/null +++ b/module/web/themes/default/js/sources/settings.coffee @@ -0,0 +1,107 @@ +root = this + +window.addEvent 'domready', -> +    root.accountDialog = new MooDialog {destroyOnHide: false} +    root.accountDialog.setContent $ 'account_box' + +    new TinyTab $$('#toptabs li a'), $$('#tabs-body > span') + +    $$('ul.nav').each (nav) -> +        new MooDropMenu nav, { +            onOpen: (el) -> el.fade 'in' +            onClose: (el) -> el.fade 'out' +            onInitialize: (el) -> el.fade('hide').set 'tween', {duration:500} +        } + +    new SettingsUI() + + +class SettingsUI +    constructor: -> +        @menu = $$ "#general-menu li" +        @menu.append $$ "#plugin-menu li" + +        @name = $ "tabsback" +        @general = $ "general_form_content" +        @plugin = $ "plugin_form_content" + +        el.addEvent 'click', @menuClick.bind(this) for el in @menu + +        $("general|submit").addEvent "click", @configSubmit.bind(this) +        $("plugin|submit").addEvent "click", @configSubmit.bind(this) + +        $("account_add").addEvent "click", (e) -> +            root.accountDialog.open() +            e.stop() + +        $("account_reset").addEvent "click", (e) -> +            root.accountDialog.close() + +        $("account_add_button").addEvent "click", @addAccount.bind(this) +        $("account_submit").addEvent "click", @submitAccounts.bind(this) + + +    menuClick: (e) -> +        [category, section] = e.target.get("id").split("|") +        name = e.target.get "text" + + +        target = if category is "general" then @general else @plugin +        target.dissolve() + +        new Request({ +            "method" : "get" +            "url" : "/json/load_config/#{category}/#{section}" +            "onSuccess": (data) => +                target.set "html", data +                target.reveal() +                this.name.set "text", name +        }).send() + + +    configSubmit: (e) -> +        category = e.target.get("id").split("|")[0]; +        form = $("#{category}_form"); + +        form.set "send", { +            "method": "post" +            "url": "/json/save_config/#{category}" +            "onSuccess" : -> +                root.notify.alert '{{ _("Settings saved.")}}', { +                            'className': 'success' +                        } +            "onFailure": -> +                root.notify.alert '{{ _("Error occured.")}}', { +                            'className': 'error' +                        } +        } +        form.send() +        e.stop() + +    addAccount: (e) -> +        form = $ "add_account_form" +        form.set "send", { +            "method": "post" +            "onSuccess" : -> window.location.reload() +            "onFailure": -> +                root.notify.alert '{{_("Error occured.")}}', { +                    'className': 'error' +                    } +            } + +        form.send() +        e.stop() + +    submitAccounts: (e) -> +        form = $ "account_form" +        form.set "send", { +             "method": "post", +             "onSuccess" : -> window.location.reload() +             "onFailure": -> +                 root.notify.alert('{{ _("Error occured.") }}', { +                             'className': 'error' +                         }); +             } + +        form.send() +        e.stop() diff --git a/module/web/themes/default/js/sources/tinytab.js b/module/web/themes/default/js/sources/tinytab.js new file mode 100644 index 000000000..de50279fc --- /dev/null +++ b/module/web/themes/default/js/sources/tinytab.js @@ -0,0 +1,43 @@ +/* +--- +description: TinyTab - Tiny and simple tab handler for Mootools. + +license: MIT-style + +authors: +- Danillo César de O. Melo + +requires: +- core/1.2.4: '*' + +provides: TinyTab + +... +*/ +(function($) { +	this.TinyTab = new Class({ +		Implements: Events, +		initialize: function(tabs, contents, opt) { +			this.tabs = tabs; +			this.contents = contents; +			if(!opt) opt = {}; +			this.css = opt.selectedClass || 'selected';  +			this.select(this.tabs[0]); +			tabs.each(function(el){ +				el.addEvent('click',function(e){ +					this.select(el); +					e.stop(); +				}.bind(this)); +			}.bind(this)); +		}, + +		select: function(el) { +			this.tabs.removeClass(this.css); +			el.addClass(this.css); +			this.contents.setStyle('display','none'); +			var content = this.contents[this.tabs.indexOf(el)]; +			content.setStyle('display','block'); +			this.fireEvent('change',[content,el]); +		} +	}); +})(document.id);
\ No newline at end of file | 
