diff --git a/build.config.js b/build.config.js
index 34aef705..7357c923 100644
--- a/build.config.js
+++ b/build.config.js
@@ -10,11 +10,6 @@ module.exports = {
src:'node_modules/angular/angular.js',
cdn:'https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js'
},
- {
- name:'angular-ui-ace',
- src:'node_modules/@rokt33r/angular-ui-ace/src/ui-ace.js',
- cdn:'https://cdn.rawgit.com/angular-ui/ui-ace/v0.2.3/ui-ace.min.js'
- },
{
name:'angular-bootstrap',
src:'node_modules/angular-bootstrap/dist/ui-bootstrap-tpls.js',
diff --git a/src/directives/tags.js b/src/directives/tags.js
new file mode 100644
index 00000000..ce2411e5
--- /dev/null
+++ b/src/directives/tags.js
@@ -0,0 +1,13 @@
+angular.module('codexen.directives')
+ .directive('tags', function () {
+ return {
+ restrict:'A',
+ template: '
'+
+ ' '+
+ '#'+
+ '
',
+ scope:{
+ tags: '='
+ }
+ }
+ })
diff --git a/src/directives/ui-ace.js b/src/directives/ui-ace.js
new file mode 100644
index 00000000..f50ee49c
--- /dev/null
+++ b/src/directives/ui-ace.js
@@ -0,0 +1,337 @@
+'use strict';
+
+/**
+ * Binds a ACE Editor widget
+ */
+angular.module('ui.ace', [])
+ .constant('uiAceConfig', {})
+ .directive('uiAce', ['uiAceConfig', function (uiAceConfig) {
+
+ if (angular.isUndefined(window.ace)) {
+ throw new Error('ui-ace need ace to work... (o rly?)');
+ }
+
+ /**
+ * Sets editor options such as the wrapping mode or the syntax checker.
+ *
+ * The supported options are:
+ *
+ *
+ * - showGutter
+ * - useWrapMode
+ * - onLoad
+ * - theme
+ * - mode
+ *
+ *
+ * @param acee
+ * @param session ACE editor session
+ * @param {object} opts Options to be set
+ */
+ var setOptions = function(acee, session, opts) {
+
+ // sets the ace worker path, if running from concatenated
+ // or minified source
+ if (angular.isDefined(opts.workerPath)) {
+ var config = window.ace.require('ace/config');
+ config.set('workerPath', opts.workerPath);
+ }
+ // ace requires loading
+ if (angular.isDefined(opts.require)) {
+ opts.require.forEach(function (n) {
+ window.ace.require(n);
+ });
+ }
+ // Boolean options
+ if (angular.isDefined(opts.showGutter)) {
+ acee.renderer.setShowGutter(opts.showGutter);
+ }
+ if (angular.isDefined(opts.useWrapMode)) {
+ session.setUseWrapMode(opts.useWrapMode);
+ }
+ if (angular.isDefined(opts.showInvisibles)) {
+ acee.renderer.setShowInvisibles(opts.showInvisibles);
+ }
+ if (angular.isDefined(opts.showIndentGuides)) {
+ acee.renderer.setDisplayIndentGuides(opts.showIndentGuides);
+ }
+ if (angular.isDefined(opts.useSoftTabs)) {
+ session.setUseSoftTabs(opts.useSoftTabs);
+ }
+ if (angular.isDefined(opts.showPrintMargin)) {
+ acee.setShowPrintMargin(opts.showPrintMargin);
+ }
+ if (angular.isDefined(opts.maxLines)) {
+ if(opts.maxLines < 0) opts.maxLines = Infinity
+ acee.setOptions({
+ maxLines: opts.maxLines
+ })
+ }
+
+ // commands
+ if (angular.isDefined(opts.disableSearch) && opts.disableSearch) {
+ acee.commands.addCommands([
+ {
+ name: 'unfind',
+ bindKey: {
+ win: 'Ctrl-F',
+ mac: 'Command-F'
+ },
+ exec: function () {
+ return false;
+ },
+ readOnly: true
+ }
+ ]);
+ }
+
+ // Basic options
+ if (angular.isString(opts.theme)) {
+ acee.setTheme('ace/theme/' + opts.theme);
+ }
+ if (angular.isString(opts.mode)) {
+ session.setMode('ace/mode/' + opts.mode);
+ }
+ // Advanced options
+ if (angular.isDefined(opts.firstLineNumber)) {
+ if (angular.isNumber(opts.firstLineNumber)) {
+ session.setOption('firstLineNumber', opts.firstLineNumber);
+ } else if (angular.isFunction(opts.firstLineNumber)) {
+ session.setOption('firstLineNumber', opts.firstLineNumber());
+ }
+ }
+
+ // advanced options
+ var key, obj;
+ if (angular.isDefined(opts.advanced)) {
+ for (key in opts.advanced) {
+ // create a javascript object with the key and value
+ obj = { name: key, value: opts.advanced[key] };
+ // try to assign the option to the ace editor
+ acee.setOption(obj.name, obj.value);
+ }
+ }
+
+ // advanced options for the renderer
+ if (angular.isDefined(opts.rendererOptions)) {
+ for (key in opts.rendererOptions) {
+ // create a javascript object with the key and value
+ obj = { name: key, value: opts.rendererOptions[key] };
+ // try to assign the option to the ace editor
+ acee.renderer.setOption(obj.name, obj.value);
+ }
+ }
+
+ // onLoad callbacks
+ angular.forEach(opts.callbacks, function (cb) {
+ if (angular.isFunction(cb)) {
+ cb(acee);
+ }
+ });
+ };
+
+ return {
+ restrict: 'EA',
+ require: '?ngModel',
+ link: function (scope, elm, attrs, ngModel) {
+
+ /**
+ * Corresponds the uiAceConfig ACE configuration.
+ * @type object
+ */
+ var options = uiAceConfig.ace || {};
+
+ /**
+ * uiAceConfig merged with user options via json in attribute or data binding
+ * @type object
+ */
+ var opts = angular.extend({}, options, scope.$eval(attrs.uiAce));
+
+ /**
+ * ACE editor
+ * @type object
+ */
+ var acee = window.ace.edit(elm[0]);
+ acee.$blockScrolling = Infinity
+
+ /**
+ * ACE editor session.
+ * @type object
+ * @see [EditSession]{@link http://ace.c9.io/#nav=api&api=edit_session}
+ */
+ var session = acee.getSession();
+
+ /**
+ * Reference to a change listener created by the listener factory.
+ * @function
+ * @see listenerFactory.onChange
+ */
+ var onChangeListener;
+
+ /**
+ * Reference to a blur listener created by the listener factory.
+ * @function
+ * @see listenerFactory.onBlur
+ */
+ var onBlurListener;
+
+ /**
+ * Calls a callback by checking its existing. The argument list
+ * is variable and thus this function is relying on the arguments
+ * object.
+ * @throws {Error} If the callback isn't a function
+ */
+ var executeUserCallback = function () {
+
+ /**
+ * The callback function grabbed from the array-like arguments
+ * object. The first argument should always be the callback.
+ *
+ * @see [arguments]{@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions_and_function_scope/arguments}
+ * @type {*}
+ */
+ var callback = arguments[0];
+
+ /**
+ * Arguments to be passed to the callback. These are taken
+ * from the array-like arguments object. The first argument
+ * is stripped because that should be the callback function.
+ *
+ * @see [arguments]{@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions_and_function_scope/arguments}
+ * @type {Array}
+ */
+ var args = Array.prototype.slice.call(arguments, 1);
+
+ if (angular.isDefined(callback)) {
+ scope.$evalAsync(function () {
+ if (angular.isFunction(callback)) {
+ callback(args);
+ } else {
+ throw new Error('ui-ace use a function as callback.');
+ }
+ });
+ }
+ };
+
+ /**
+ * Listener factory. Until now only change listeners can be created.
+ * @type object
+ */
+ var listenerFactory = {
+ /**
+ * Creates a change listener which propagates the change event
+ * and the editor session to the callback from the user option
+ * onChange. It might be exchanged during runtime, if this
+ * happens the old listener will be unbound.
+ *
+ * @param callback callback function defined in the user options
+ * @see onChangeListener
+ */
+ onChange: function (callback) {
+ return function (e) {
+ var newValue = session.getValue();
+
+ if (ngModel && newValue !== ngModel.$viewValue &&
+ // HACK make sure to only trigger the apply outside of the
+ // digest loop 'cause ACE is actually using this callback
+ // for any text transformation !
+ !scope.$$phase && !scope.$root.$$phase) {
+ scope.$evalAsync(function () {
+ ngModel.$setViewValue(newValue);
+ });
+ }
+
+ executeUserCallback(callback, e, acee);
+ };
+ },
+ /**
+ * Creates a blur listener which propagates the editor session
+ * to the callback from the user option onBlur. It might be
+ * exchanged during runtime, if this happens the old listener
+ * will be unbound.
+ *
+ * @param callback callback function defined in the user options
+ * @see onBlurListener
+ */
+ onBlur: function (callback) {
+ return function () {
+ executeUserCallback(callback, acee);
+ };
+ }
+ };
+
+ attrs.$observe('readonly', function (value) {
+ acee.setReadOnly(!!value || value === '');
+ });
+
+ // Value Blind
+ if (ngModel) {
+ ngModel.$formatters.push(function (value) {
+ if (angular.isUndefined(value) || value === null) {
+ return '';
+ }
+ else if (angular.isObject(value) || angular.isArray(value)) {
+ throw new Error('ui-ace cannot use an object or an array as a model');
+ }
+ return value;
+ });
+
+ ngModel.$render = function () {
+ session.setValue(ngModel.$viewValue);
+ };
+ }
+
+ // Listen for option updates
+ var updateOptions = function (current, previous) {
+ if (current === previous) return;
+ opts = angular.extend({}, options, scope.$eval(attrs.uiAce));
+
+ opts.callbacks = [ opts.onLoad ];
+ if (opts.onLoad !== options.onLoad) {
+ // also call the global onLoad handler
+ opts.callbacks.unshift(options.onLoad);
+ }
+
+ // EVENTS
+
+ // unbind old change listener
+ session.removeListener('change', onChangeListener);
+
+ // bind new change listener
+ onChangeListener = listenerFactory.onChange(opts.onChange);
+ session.on('change', onChangeListener);
+
+ // unbind old blur listener
+ //session.removeListener('blur', onBlurListener);
+ acee.removeListener('blur', onBlurListener);
+
+ // bind new blur listener
+ onBlurListener = listenerFactory.onBlur(opts.onBlur);
+ acee.on('blur', onBlurListener);
+
+ setOptions(acee, session, opts);
+ };
+
+ scope.$watch(attrs.uiAce, updateOptions, /* deep watch */ true);
+
+ // set the options here, even if we try to watch later, if this
+ // line is missing things go wrong (and the tests will also fail)
+ updateOptions(options);
+
+ elm.on('$destroy', function () {
+ acee.session.$stopWorker();
+ acee.destroy();
+ });
+
+ scope.$watch(function() {
+ return [elm[0].offsetWidth, elm[0].offsetHeight];
+ }, function() {
+ acee.resize();
+ acee.renderer.updateFull();
+ }, true);
+
+ scope.Infinity = -1
+
+ }
+ };
+ }]);
diff --git a/src/index.html b/src/index.html
index a308531b..73b43295 100644
--- a/src/index.html
+++ b/src/index.html
@@ -26,7 +26,6 @@
-
diff --git a/src/modals/new-snippet-modal.js b/src/modals/new-snippet-modal.js
index 8ea5f694..28b18bb6 100644
--- a/src/modals/new-snippet-modal.js
+++ b/src/modals/new-snippet-modal.js
@@ -18,9 +18,8 @@ angular.module('codexen.modals')
vm.submit = function () {
var params = {
- title: vm.title,
description: vm.description,
- prefix: vm.prefix,
+ callSign: vm.callSign,
mode: vm.mode==null?null:vm.mode.name.toLowerCase(),
content: vm.content,
tags: angular.isArray(vm.tags)?vm.tags.map(function (tag) { return {_id: tag._id, name: tag.name} }):[]
diff --git a/src/modals/new-snippet-modal.tpl.html b/src/modals/new-snippet-modal.tpl.html
index 84e838ac..aa810d8b 100644
--- a/src/modals/new-snippet-modal.tpl.html
+++ b/src/modals/new-snippet-modal.tpl.html
@@ -1,6 +1,6 @@
@@ -8,7 +8,7 @@
-
+
{{$select.selected.name}}
@@ -18,13 +18,15 @@
-
+
+ }"
+ ng-model="vm.content"
+ >
+
diff --git a/src/states/home/home.tpl.html b/src/states/home/home.tpl.html
index 007d21cb..651752f8 100644
--- a/src/states/home/home.tpl.html
+++ b/src/states/home/home.tpl.html
@@ -5,6 +5,9 @@
App: Rokt33r/codexen-app
Server: Rokt33r/codexen-server
+
+
+ © 2015 MAISIN&CO.,Inc.
diff --git a/src/states/snippets/detail.tpl.html b/src/states/snippets/detail.tpl.html
index deecb1e9..0748b984 100644
--- a/src/states/snippets/detail.tpl.html
+++ b/src/states/snippets/detail.tpl.html
@@ -1,9 +1,7 @@
-
-
-
-
+
-
-
-
-
+
diff --git a/src/states/snippets/snippets.scss b/src/states/snippets/snippets.scss
index 867922fd..62754ad3 100644
--- a/src/states/snippets/snippets.scss
+++ b/src/states/snippets/snippets.scss
@@ -47,6 +47,8 @@ $snippet-list-item-hover-bg: #EEE;
bottom: 0;
left: $left-pane-width;
right: 0;
+ overflow-x: hidden;
+ overflow-y: auto;
}
}
@@ -69,13 +71,14 @@ $snippet-list-item-hover-bg: #EEE;
.detail-body{
padding: 5px 10px;
.ace_editor {
- height: 500px;
+ min-height: 300px;
border: solid 1px $border-color;
border-radius: 5px;
}
}
}
.tags{
+ word-break: break-all;
a{
margin: 0 2px;
}